I know that reflection is nothing new, in fact many people may even call it old hat. However, it does still have its place and can still be very, very useful. The other day I wanted to write a set of tests which would ensure that out developers put the [Serializable] attribute on all our service request/response objects. We must have this attribute on these objects because we are dealing with a remoting boundary. The reason I wanted to add this test is because many times when we create objects which must cross our boundary we forget to put the [Serializable] attribute on our class and we have to wait until runtime to learn our fate. What makes this test easy for us is that we have a standard convention which will allow for us to search for and find all our Response and Request objects (yea conventions)
The good news for us is that Reflection makes writing this test very easy and very straight forward.
Before we start to dive into the code we should take a look at a ‘standard’ response class
[Serializable]
public class DoSomethingResponse
{
// body goes here
}
Now that we have seen an example Response object (I know, I know it was a lame example but deal with me here) we need to take a look at the logic which allows us to find our attributes via reflection.
The code below is NOT the unit test code, but it is the reflection guts which will be called by my unit tests
private StringBuilder SearchForTypes( Assembly assembly, string searchSuffix )
{
var stringBuilder = new StringBuilder();
// #1
foreach ( var type in assembly.GetTypes() )
{
bool foundSerializableAttribute = false;
// #2
if ( type.Name.EndsWith( searchSuffix ) )
{
// #3
var customAttributes = type.GetCustomAttributes( typeof( TYPE ), true );
// #4
if ( customAttributes == null )
{
stringBuilder.AppendLine( string.Format( "Type {0} is missing the serializable attribute", type.Name ) );
}
}
}
return stringBuilder;
}
Looking at the code above there are a few items I should point out
- This will loop through all the types for the given loaded assembly. This will look for both public and private types
- When find a type, we want to check its name to see if the naming on the class matches the naming convention we are looking for (DoSomethingResponse is a Response convention)
- We want to pull All custom attributes for the given type (System.Serializable) off the class
- We want to make sure there was an attribute found, if there was NOT then we want to log that for later.
The code below is the unit test code which will call the code above.
[Test]
public void Response_EnsureAllResponseClassesAreSerializable()
{
var assembly = Assembly.GetAssembly( typeof( IRemotingServiceMarker ) );
var stringBuilder = SearchForTypes( assembly, "Response" );
Assert.That( stringBuilder.Length == 0, stringBuilder.ToString() );
}
The test above is pretty straight forward, we are loading the assembly based on a type in the assembly then we simply call off to our method we defined above. Because we do not want to simply fail on the first missing class we will return a list of any classes which should contain our marker, but do not.
As you can see, using reflection to find markers on a class is pretty easy.
Till next time,
Posted
08-04-2009 7:22 AM
by
Derik Whittaker