Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange behavior with NUnit, ExpectedException & yield return

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?

like image 659
Carl-Otto Kjellkvist Avatar asked Nov 26 '11 12:11

Carl-Otto Kjellkvist


1 Answers

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);
            }
        }
    }
like image 142
anderbakk Avatar answered Nov 18 '22 01:11

anderbakk