Search code examples
c#unit-testingcompilationstrong-typing

How to unit test C# code that's expected to fail compilation for negative testing?


We're meant to generate a string output that's required to adhere to a particular set of syntactical rules. I created an object model in order to enforce that syntax via C#'s strong-typing with the intent to prevent the possibility of generating invalid output.

I can create positive tests, i.e. valid C# generating valid output. What I'm unable to do is run negative tests, i.e. ensuring that attempting to generate invalid output will throw errors at compilation.

Explicit example:

namespace Abstract
{
    public interface FooType { }
    public interface FooString : FooType { }
}

public interface Integer : Abstract.FooType { }    
public interface SingleLine : Abstract.FooString { }
public interface MultiLine : Abstract.FooString { }

public class Bar<T>
    where T : Abstract.FooType
{
    public Bar(string s) {
        // do stuff with s and T, where T is SingleLine or MultiLine
    }

    public Bar(int i) {
        // do stuff with i and T, where T is Integer
    }
}

public static class Foo
{
    public static Bar<T> Bar<T>(int i) where T : Integer {
        return new Bar<T>(i);
    }

    public static Bar<SingleLine> Bar(string s) {
        return new Bar<SingleLine>(s);
    }

    public static Bar<T> Bar<T>(string s) where T : Abstract.FooString {
        return new Bar<T>(s);
    }
}

All of that just so I can do:

Foo.Bar<SingleLine>("some string");  // ok
Foo.Bar("another string");           // ok
Foo.Bar<MultiLine>("more\nstrings"); // still ok
Foo.Bar<Integer>(24)                 // also ok

// How to test these lines for compilation failure?
Foo.Bar<Integer>("no good");
Foo.Bar<MultiLine>(-1);

In case it matters, I'm using VS2012 Express for Desktop.


Solution

  • Sure you can, just craft the code snippet that you want to fail to compile (as a string, or load a .cs file into a string) and invoke the C# compiler on it using the CodeDom. Your test then just needs to check that the compiler failed, and if you like check the line number error message etc... is correct.

    Of course this is a fair amount of effort - you need to evaluate how much gain this is really going to get you. If you are developing some sort of API that other developers are going to use, and this is an important feature that may well inadvertantly break in the future through some subtle change then you may want to unit test this. Otherwise this is probably going to be a lot of effort for little reward (IMO).