Testing generated code

time to read 10 min | 1838 words

A couple of days ago I asked about how to test that code that generates code. Basically, there are two or three options:

  • String comparisions - Fragile, but easiest to do.
  • Use a C# Parser and check the resulting DOM
  • Compile the code and test that

I went with the third option, mostly because it was the easiest to write. I had another project where I tried the strings approach, and I ended up not running the tests because they were so fragile.

Here it the first test that I wrote (the project here in NHibernate Query Generator):

[Test]

public void CanGenerateCodeThatDoesnotProduceErrors()

{

       StringBuilder sb = new StringBuilder();

       TextReader reader = new StreamReader(GetSampleStream());

       TextWriter writer = new StringWriter(sb);

       QueryGenerator generator = new QueryGenerator(reader, new CSharpCodeProvider());

       generator.Generate(writer);

       string code = sb.ToString();

       CodeDomProvider provider = new CSharpCodeProvider();

       CompilerParameters cp = new CompilerParameters();

       cp.GenerateInMemory = true;

       cp.OutputAssembly = "Generated.Context";

       cp.ReferencedAssemblies.Add(typeof(ISession).Assembly.Location);//nhibernate

       cp.ReferencedAssemblies.Add(typeof(NamedExpression).Assembly.Location); // named expression library

       CompilerResults results =  provider.CompileAssemblyFromSource(cp, code);

       Assert.AreEqual(0, results.Errors.Count);

}

After writing this, I compiled and run, and it worked. Empty code appears to compile, so I refactored a bit, moved things to the Setup and util methods (CompileCode(), AssertCodeCompiles() and GetAssemblyFromCode).

Then, it was time to write a meaningful test, like this one:

[Test]

public void GeneratedAssemblyHasWhereTypeWithNestedCustomerType()

{

    Assembly asm = GetAssemblyFromCode();

 

    System.Type whereType = asm.GetType("Query.Where");

    Assert.IsNotNull(whereType, "Should have gotten an assembly with a where type");

 

    PropertyInfo customerProperty = whereType.GetProperty("Customer");

   

    Assert.IsNotNull(customerProperty, "Where type should have property Customer");

}

Since I have compilable code, I can use Reflection to verify that I generated the code that I wanted. From there, it was a simple matter of writing a test using Reflection, and then writing the code that would generate the expected output.