Reputation: 527
I know that this is probably quite easy, but since I've just started learning unit testing, I'm a little confused with all of the possibilities.
I've got this pretty simple method which should read integers numbers from file (the condition is that file contains only integer numbers, each of them stored in a new line).
public static IEnumerable<int> ReadIntegers(string file)
{
using (var stream = File.OpenText(file))
{
string line;
while ((line = stream.ReadLine()) != null)
{
yield return int.Parse(line);
}
}
}
One thing before I continue, please don't suggest me to refactor method, I've found it and I want to learn how to write unit test for this particular input parameter and output value.
I've found on the another topic that someone suggested to create a testfile in test case and than try to compare expected with actual result, something like this :
[Test]
public void ShouldValidateReadingOfTheFile()
{
string path = @"E:\TestFile.txt";
using (var sw = File.AppendText(path))
{
sw.WriteLine(1);
sw.WriteLine(100);
}
var expected = new List<int>() { 1, 100 };
var actual = TestProject.Merge.ReadIntegersFromFile(path);
Assert.IsTrue(expected.SequenceEqual(actual));
}
I want to ask you is this a bad practice ? Do you have different approach ? Is there any other idea about different tests for this method.Thank You !
Upvotes: 5
Views: 4054
Reputation: 745
You can unit test your method without refactoring it using typemock framework, here is an example for your code:
[TestMethod, Isolated]
public void ShouldValidateReadingOfTheFile()
{
var fileContents =
@"1
100";
StreamReader reader = new StreamReader(
new MemoryStream(Encoding.ASCII.GetBytes(fileContents)));
Isolate.WhenCalled(() => File.OpenText("fake")).WillReturn(reader);
var result = Class1.ReadIntegers("fake").ToArray();
var resList = new int[] {1, 100};
CollectionAssert.AreEquivalent(resList, result);
}
i hope this will help you to better understand unit testing.
Upvotes: 2
Reputation: 4113
I would split the method in 2
public static IEnumerable<int> ReadIntegers(Stream file)
{
///... your code here
}
and
public static IEnumerable<int> ReadIntegers(string file)
{
var stream = File.OpenText(file);
return ReadIntegers(stream)
}
and for the unit tests themselves:
[Test]
public void ShouldValidateReadingOfTheFile()
{
string stream = new MemoryStream();
using (var sw = StreamWiter(stream))
{
sw.WriteLine(1);
sw.WriteLine(100);
}
var expected = new List<int>() { 1, 100 };
var actual = TestProject.Merge.ReadIntegersFromFile(path);
Assert.IsTrue(expected.SequenceEqual(actual));
}
what I did was to wrap the MemoryStream
with a StreamWriter
so it was easy to write the lines an populate the values I wanted. That should do it.
You can then use the same strategy to test all other cases and make a helper like this:
private Stream GetStream(IEnumerable<int> values)
{
string stream = new MemoryStream();
using (var sw = StreamWiter(stream))
{
foreach(int i in values)
sw.WriteLine(i);
}
return stream;
}
or something similar. With this approach you can do all the testing you want on the method that does the actual work (the one with the Stream
parameter) and if you still need to test the file opening (string
to Stream
) code then you could use a test file within your project so you can test it, although I don't see the point of it since you'd be testing the framework's ability to work with files, if the file name comes from within your code, then it's a better idea to test the filename generating code instead. Hope this helps. Happy coding
Upvotes: 2
Reputation: 3968
I think you can do the unit-testing
this way but I would suggest you to test also special cases.
E.g.
null
as file nameAnd creating test files is a common practice.
Upvotes: 3