I am working on a large project where a base class has thousands of classes derived from it (multiple developers are working on them). Each class is expected to override a set of methods. I first generated these thousands of class files with a code template that conforms to an acceptable pattern. I am now writing unit tests to ensure that developers have not deviated from this pattern. Here is a sample generated class:
// Base class.
public abstract partial class BaseClass
{
protected abstract bool OnTest ();
}
// Derived class. DO NOT CHANGE THE CLASS NAME!
public sealed partial class DerivedClass_00000001: BaseClass
{
/// <summary>
/// Do not modify the code template in any way.
/// Write code only in the try and finally blocks in this method.
/// </summary>
protected override void OnTest ()
{
bool result = false;
ComObject com = null;
// Declare ALL value and reference type variables here. NOWHERE ELSE!
// Variables that would otherwise be narrowly scoped should also be declared here.
// Initialize all reference types to [null]. [object o;] does not conform. [object o = null;] conforms.
// Initialize all value types to their default values. [int x;] does not conform. [int x = 0;] conforms.
try
{
com = new ComObject();
// Process COM objects here.
// Do NOT return out of this function yourself!
}
finally
{
// Release all COM objects.
System.Runtime.InteropServices.Marshal.ReleaseComObject(com);
// Set all COM objects to [null].
// The base class will take care of explicit garbage collection.
com = null;
}
return (result);
}
}
In the unit tests, I have been able to verify the following via reflection:
- The class derives from [BaseClass] and does not implement any interfaces.
- The class name conforms to a pattern.
- The catch block has not been filtered.
- No other catch blocks have been added.
- No class level fields or properties have been declared.
- All method value type variables have been manually initialized upon declaration.
- No other methods have been added to the derived classes.
The above is easily achieved via reflection but I am struggling with asserting the following list:
- The catch block re-throws the caught exception rather than wrapping it or throwing some other exception.
- The
[return (result);]
line at the end has not been modified and no other[return (whatever);]
calls have been added. No idea how to achieve this. - Verify that all reference types implementing IDisposable have been disposed.
- Verify that all reference types of type [System.__ComObject] have been manually de-referenced and set to [null] in the finally block.
I have thought about parsing the source code but I don't like that solution unless absolutely necessary. It is messy and unless I have expression trees, almost impossible to guarantee success.
Any tips would be appreciated.