Friday, January 8, 2016

Method doesn't throw ArgumentNullException when expected

I noticed an interesting test failure when I refactored a method to use the recently added C# keyword 'yeild'.
    public class Subject
    {
        public IEnumerable<string> DoWork(string foo)
        {
            if (foo == null) throw new ArgumentNullException(nameof(foo));
            var someCollection = Enumerable.Range(0, 100);
            foreach (var number in someCollection)
            {
                yield return foo + number.ToString("C");
            }
        }
    }


The above method is, of course, a contrived and simplified example.
Here is the unit test for this method to check that ArgumentNullException is thrown.

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DoWork_ShouldThrow_GivenNullFoo()
        {
            var subject = new Subject();
            var result = subject.DoWork(null);
            Assert.Fail();
        }

This test does not pass in its current form. The thread reaches the Assert.Fail() and the test fails.


Assert.Fail failed. 

   at MyAssemblyTest.SubjectTest.DoWork_ShouldThrow_GivenNullFoo() in C:\... line 55
If you're like me and seldom use the yield keyword, it takes a while to realise that the yield keyword triggers delayed execution of the entire method. Meaning the methods doesn't actually run until you access the collection that is returned. When the collection is accessed the exception is thrown.

Here's my modified unit test to cater for this:

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void DoWork_ShouldThrow_GivenNullFoo()
        {
            var subject = new Subject();
            var result = subject.DoWork(null);
            result.Any();
            Assert.Fail();
        }