I have a strange behavior in a tests where I want to test that an exception is thrown when null is passed in as a parameter. When I run the test I get from NUnit:
System.ArgumentNullException was expected
-- Exception doesn't have a stack trace --
My test:
[Test]
[ExpectedException(typeof(ArgumentNullException))]
public void Should_not_retrieve_any_fields_when_file_is_null()
{
_creator.CreateFields(null);
}
My implementation:
public IEnumerable<ImportField> CreateFields(HttpPostedFileBase file)
{
if (file == null) throw new ArgumentNullException("file");
using (var reader = new StreamReader(file.InputStream))
{
var firstLine = reader.ReadLine();
var columns = firstLine.Split(new[] { ',' });
for (var i = 0; i < columns.Length; i++)
{
yield return new ImportField(columns[i], i);
}
}
}
Is there a logical explanation to this behavior and should I make my implementation differently?
The reason you're getting this behaviour is because of the yield keyword. When using yield, the compiler will generate a class for the method with the yield in it. When calling that method, control is unconditionally returned to back to the caller. Nothing in your method is actually executed before it is need.
If you extract your using statement into a separate method and return the result, your test will pass. Or you can store the result to a variable in your test, and for example call "ToList()" on it.
public IEnumerable<ImportField> CreateFields(HttpPostedFileBase file)
{
if (file == null) throw new ArgumentNullException("file");
return ExtractFromFile(file);
}
private IEnumerable<ImportField> ExtractFromFile(HttpPostedFileBase file)
{
using (var reader = new StreamReader(file.InputStream))
{
var firstLine = reader.ReadLine();
var columns = firstLine.Split(new[] { ',' });
for (var i = 0; i < columns.Length; i++)
{
yield return new ImportField(columns[i], i);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With