I’ve been spending much of my time working on a multi-tier system that makes use of special purpose data transfer objects for communication between the service tier and various clients.

These dedicated data transfer objects need to be properly marked up with [DataContract] and [DataMember] attributes, else the object is incomplete when transferred over the wire.

Unfortunately, any errors in the markup weren’t apparent at compile time. Instead, they were being discovered either at runtime, when a service call failed outright, or while writing client code, when an expected property was missing from a proxy generated by svcutil.

Enter NUnit to save the day with a cunning unit test.

[Test]
public void PublicPropertiesOfDataTransferObjects_shouldHaveDataMemberAttribute()
{

We begin by finding all the candidate data transfer object classes - every descendant of the base class DataTransferObject found in the appropriate assembly.

var dtoTypes
    = typeof(InstrumentDTO).Assembly
        .GetExportedTypes()
        .Where(t => typeof(DataTransferObject)
                    .IsAssignableFrom(t))
        .ToList();

Then we iterate over all the properties declared on those classes to find all the properties that have not been flagged with either [DataMember] or [IgnoreDataMember]. The later attribute allows you to explicitly opt out of the data contract serializer if you want.

var invalidProperties
    = dtoTypes.SelectMany(t => t.GetProperties())
        .Where(p => !PropertyHasDataMemberAttribute(p)
            && !PropertyHasIgnoreDataMemberAttribute(p))
        .ToList();

The test needs to do more than fail the build if there is a problem. It also needs to tell us where to fix the problem, so we generate a diagnostic message listing all of the invalid properties.

var violations
    = "Found "
      + invalidProperties.Select(
          p => string.Format("{0}.{1}", 
                             p.DeclaringType.Name, 
                             p.Name))
            .JoinWith("; ");

JoinWith() is a simple utility extension method that combines a sequence of strings together with a specified separator.

With all of the information gathered in, we can write our test to ensure that there are no invalid properties in our project.

    Assert.That(invalidProperties.Count, 
                Is.EqualTo(0), 
                violations);
}

NUnit can be used for more than testing the functionality of small pieces of code - it can also be used to enforce coding conventions and to catch problems early.

Do you have a critical convention in your system that could be enforced by this kind of an assembly wide unit test?

Comments

blog comments powered by Disqus