Last Updated: February 25, 2016
·
7.983K
· spoike

Dynamic Unit-Tests in C#

Getting build failure from automated test-runners (such as NCrunch) can be quite annoying. But is it possible to write tests without receiving any build errors as feedback in C#? Well, with the dynamic keyword you can!

This tip is actually from @markrendle, who showed this in the #leetspeak12 conference. However I couldn't find any article describing this so I'll just post the idea here.

Step 1. Create a Dynamic Type Factory

If you really want to be able to initially unit test a class that doesn't exist yet, without any build errors, you can start by creating a handy-dandy factory helper that builds your types dynamically like this:

class TypeFactory {
    public static dynamic Build { 
        get { 
            return new TypeFactory(); 
        } 
    }
}

That was simple, no?

The factory method (which is technically a property in this case called Build) will return an instance of the factory class as a dynamic, i.e. a certain something with properties and methods that will be resolved during runtime. Because of this you can use the dynamic factory to create anything of any type, even objects of types that haven't been defined yet, directly in your tests.

The example below uses the dynamic factory by invoking the Build property followed by another property that should create our currently undefined object like this:

var myNewObj = TypeFactory.Build.MyNewObj;

This snippet of code won't show any build errors but will throw during runtime a RuntimeBinderException as TypeFactory does not have a MyNewObj property implemented nor is it dynamically set. But that's enough for us to write the first failing test and the idea is to extend the factory as you create new types for your tests. We'll continue with an example below.

Step 2. Create a Unit Test that Tests Something of an Unknown type - Make it Red

Say we want to create a class named Roman, that generates roman numerals from arabic numerals both represented as a string and integer respectively.

So let us start out with a simple test case before we write the class (in lieu with red-green-refactor mantra of TDD). As explained above we can get any type from the dynamic factory through the TypeFactory.Build getter property followed by the property getter that builds the type you want, we'll go with the name Roman:

[Test]
public void RomanNumeralOne() {
    var roman = TypeFactory.Build.Roman;

    Assert.That(r.ToRoman(1), Is.EqualTo("I");
}

Do note that we have no build errors here, even if there is nothing in the TypeFactory that has the Roman property. However, as expected during execution, the test will become red due to a RuntimeBinderException. Implementing this testcase will be easy.

Step 3. Fix the Failing Test - Make it Green

Lets start with modifying the type factory to return the new object:

public class TypeFactory {
    // ... keep the Build property

    public Roman Roman { get { return new Roman(); } }
}

Using Resharper or Coderush, the generation of the new class (with the simplest thing that could possibly work for the test) should be ridiculously quick and easy:

public class Roman {
    public string ToRoman(int arabic) { return "I" };
}

The test should be green. Lather, rinse, repeat from step 2. Continue on with TDD:ing to implement the rest of the class.

Step 4. Profit!

Happy TDD:ing!