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();
        }

Sunday, August 9, 2015

Convert existing event handler invocations to C#6 Null Propagation

Search for:

if \(handler \!= null\)\s*\r?\n\s*\{\r?\n\s*handler\((?<args>.*?)\);\r?\n\s*\}
and replace using:
handler?.Invoke(${args});

For example, this will be matched and replaced

if (handler != null)
{
    handler(this, new DialogResponseEventArgs(id, true));
}

with this
handler?.Invoke(this, new DialogResponseEventArgs(this.dialogCorrelationId, message.Response == ShellDialogButton.Cancel));

Converting existing code to use C#6 Expression Bodied Properties

Converting all types of Simple Properties

Search for

[^\S\r\n]+(?<accessor>\w+)(?<override> override | )(?<typename>\w+) (?<pname>.*?)\r?\n\s*\{\r?\n\s*get(\r?\n)*\s*\{\s*return (?<returnexpr>.*?);\s*\}\s*\}
and replace with
${accessor} ${override}${typename} ${pname} => ${returnexpr};

For example the following properties will be matched and converted:

public override string Description 
{
    get 
    {
        return "The quick brown fox jumped over the lazy dog.";
    }
}
public string Description 
{
    get 
    {
        return "The quick brown fox jumped over the lazy dog.";
    }
}
public string Description 
{
    get { return "The quick brown fox jumped over the lazy dog."; }
}
public bool HasValue 
{
    get { return this.field; }
}
public virtual IEnumerable<BudgetBucket> Buckets
{
    get { return this.lookupTable.Values.OrderBy(b => b.Code).ToList(); }
}

All the above are changed to the new syntax:
public override string Description => "The quick brown fox jumped over the lazy dog.";

Converting existing code to use nameof() in C# 6

Now with the new C#6 nameof operator, the use of ArgumentNullExceptions and ArgumentExceptions become more flexible and resistant to variable refactoring and renaming.

ArgumentNullException

Here's a regex to search and replace in Visual Studio usage of ArgumentNullException: Search for:
throw new ArgumentNullException("(?<message>.*?)
Replace with:
throw new ArgumentNullException(nameof(${varname})

For example this will replace this
throw new ArgumentNullException("variable", "This variable cannot be null.");
with
throw new ArgumentNullException(nameof(variable), "This variable cannot be null.");

ArgumentException

Here's another regex to search and replace usage of ArgumentException: Search for:
throw new ArgumentException\("(?<message>.*?)", "(?<varname>.*?)"
Replace with:
throw new ArgumentException("${message}", nameof(${varname})
For example this will replace this
throw new ArgumentException("This argument is invalid for some weird reason.", "variable");
with
throw new ArgumentException("This argument is invalid for some weird reason.", nameof(variable));