0
string _inboundFilePath = AppDomain.CurrentDomain.BaseDirectory + @"\Inbound\CompareDataFile.csv";

var mockReaderStream = new Mock<IReaderStream>();
mockReaderStream.Setup(x => x.CreateStream())
    .Returns(new System.IO.StreamReader(_inboundFilePath));

Here I am dependent on an inbound file to read data from and then perform other function checks. my question is how to avoid this? In this case I am checking data for a particular id that comes in from the csv.

Igor
  • 60,821
  • 10
  • 100
  • 175
Tiger
  • 59
  • 10
  • 2
    If you only need a stream, you could use an embedded resource, and load *that* in your test - not `FileStream` required. Or if you only need a `TextReader`, embed the data in the source code as a string and return a `StringReader`. (Only good if you've got a small amount of data though.) – Jon Skeet Sep 05 '18 at 13:29
  • is embedded resource better solution ? i searched a lot a part from this and did not found anything , mostly my test cases are dependent on csv – Tiger Sep 05 '18 at 13:47
  • Embedded resources are pretty simple, and mean you can keep the file in its natural form in source control. You don't need to worry about finding the base directory - you just load it from the assembly. I've certainly used it to great effect in the past. – Jon Skeet Sep 05 '18 at 19:45

2 Answers2

4

It is not likely to be a good practice because a unit test must be deterministic. It means that whatever the situation, you must be sure that if this test runs, it will do exactly the same than before.

If you read a csv file, the test will depend on the external world. And unfortunately, the external world is not stable. For a start somebody can change the csv file.

That is why it is a better practice to get the csv file stream from a an embedded resource in the assembly instead of getting it from a file on the hard drive.

Stephane
  • 1,359
  • 1
  • 15
  • 27
  • Correct ! Waiting for others to comment here , but this will be the better solution to avoid file the physical path – Tiger Sep 06 '18 at 13:07
0

In addition to the answer from Stephane. I will suggest you:

  1. Put @"\Inbound\CompareDataFile.csv" to config file.

  2. Create public property or separate method in the aforementioned class that will be able to retrieve and return the inbound file absolute path (call it GetPath).

  3. Create UnitTest method that have access to the config file. This TestMethod must read config files, call AppDomain.CurrentDomain.BaseDirectory. So this method could also retrieve the path of inbound file absolute path and after this call GetPath()

  4. Create abstraction (interface or abstract class above Mock - (it's not a mock by the way in the code you've provided, so hard to guess why you call it so)).

  5. Create public method in the aforementioned class that will require an object of the abstraction and call its method ReadFromCsv().

  6. Create Test class (mock) that will implement this abstraction and will return desired/undesired values when you call it's method ReadFromCsv().

  7. Finally, test your class.

PS. This is not a strict algorithm of testing the class, you can use it. By what you would like to get from all this seven items is the notion of unit-test-likeness.

Also you do not free your class from config file, so, use this approach to free your class from config: How to mock ConfigurationManager.AppSettings with moq

JohnIdlewood
  • 356
  • 3
  • 12
  • I don't see any reason to put the filename in a configuration file. The production code doesn't need to get at it at all. Why add a layer of indirection with no benefit? – Jon Skeet Sep 05 '18 at 14:30
  • Your Intergration test class will access the config file also. And instead of unit testing method that returns absolute path by Asserting that return value equals an actual string (will require to put the desired string into the TestMethod also - data duplicate - potential error) you'll get a repeatable stable test, that will return the same result. The developer has to change @"\Inbound\CompareDataFile.csv" only in config files. But when having the same string in two methods may cause an error and the developer (probably other person) will spend time trying to find the cause of test failure. – JohnIdlewood Sep 05 '18 at 14:55
  • Why would it be in two files? Where's the assertion of the string? I don't see anything in the question suggesting any such thing. As far as I can see, the OP doesn't really care that the data is in a physical file - they just want a good way of obtaining that test data. For me, putting it in an embedded resource in the test assembly is the best way to do that. – Jon Skeet Sep 05 '18 at 19:44