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):
public void CanGenerateCodeThatDoesnotProduceErrors()
StringBuilder sb = new StringBuilder();
TextReader reader = new StreamReader(GetSampleStream());
TextWriter writer = new StringWriter(sb);
QueryGenerator generator = new QueryGenerator(reader, new CSharpCodeProvider());
string code = sb.ToString();
CodeDomProvider provider = new CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
cp.GenerateInMemory = true;
cp.OutputAssembly = "Generated.Context";
cp.ReferencedAssemblies.Add(typeof(NamedExpression).Assembly.Location); // named expression library
CompilerResults results = provider.CompileAssemblyFromSource(cp, code);
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:
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.