Mistake proofing

In previous posts I described how I test serialization of objects.

However, I still forget to do this. So, I’ve written tests to remind me. This is an idea from Lean engineering called poka yoke (see http://en.wikipedia.org/wiki/Poka-yoke).

The concept is simple – make it impossible or hard for someone to make mistakes that go unnoticed.

I use the convention of putting all the classes that need to be serialized in a contracts namespace. This makes it simple to write a test to check all these classes are defined with the DataContract attribute.

        [Test]
        public void All_classes_in_contract_namespace_should_implement_datacontract()
        {
            IList allClassesInContractsNamespace = ReflectionHelper.GetAllTypesWhere(x=>x.Namespace.Contains("Contracts") && x.IsClass).ToList();

            allClassesInContractsNamespace.Count.ShouldBeGreaterThan(0);

            foreach (object obj in allClassesInContractsNamespace)
            {
                var dataContract = obj.GetType().GetCustomAttributes(typeof(DataContractAttribute), false).OfType().FirstOrDefault();
                dataContract.ShouldNotBe(null);
            }
        }

The ReflectionHelper extension method encapsulates how I’m using Autofac to get a list of types. This makes it simpler to re-use in my tests as well as change the method of reflecting over types in the future;

public static IEnumerable GetAllTypesWhere(Func predicate)
        {
            var builder = new ContainerBuilder();
            builder.RegisterAssemblyTypes(typeof(Invoice).Assembly)
                   .Where(predicate.Invoke)
                   .As();

            IContainer container = builder.Build();
            var controllers = container.Resolve<IEnumerable>();

            return controllers;
        }

This technique can be extended to any frequent mistake.

Conclusion

We have a lot of tools to help us not make mistakes; modern development tools help a lot. Third party tools exist such as re-sharper, style-cop, and FxCop. Our build systems run our unit tests and these static analysis tools.

We can take this further by writing tests that check for our most common mistakes.

Testing serialization part II

My previous post on testing serialization was in-complete.  Since then my tests have evolved enough to warrant another post (at least I think so).

Here’s the excerpt from my previous post;

[Test]
public void Should_Serialise_across_service_boundary()
{
    var s = new DataContractSerializer(typeof(BankAccount));
    var account = new BankAccount() { Owner = new Person() };
    s.WriteObject(new MemoryStream(), account);
}

So, what are the shortcomings I’d like to address?

  • The test doesn’t assert anything. As long as the serializer doesn’t throw an exception, the test passes
  • It isn’t particuarly readable and we’ll probably end up with a lot of code duplication

However, before addressing the above issues I’d like to explain why we became interested in testing serialisation and how we failed to solve this previously.

Motivation

Unlike my normal tests this is not a TDD practise.  TDD is about driving your design through tests.  This is not my motivation for doing this type of test.

These tests are supporting continuous integration by providing early feedback.

On the project I was designing at the time we’d spent some time tracking down the cause of defects that turned out to be serialization issues.

First attempt

To address this we starting creating a comprehensive set of integration and acceptance tests. However, these took too long to run and we realised things would only get worse as our system grew.

Also, detecting these problems in integration tests increases the feedback loop. This is bad. It would be much better to find these problems sooner – preferably in unit tests.

Unit testing serialization

So let’s get back to the tests.

Take the following classes;

public class BankAccount
{
    public string AccountNumber { get; set; }
    public string SortCode { get; set; }
    public Person Owner { get; set;}

public class Person
{
    public string Name { get; set; }
    public DateTime DateOfBirth { get; set; }
}

BankAccount and Person are simple classes, so I’m confident this will serialize correctly.

Now, how about after refactoring this to use interfaces;

public class BankAccount
{
    public string AccountNumber { get; set; }
    public string SortCode { get; set; }
    public IParty Owner { get; set; }
}

public class Person : IParty
{
    public string Name { get; set; }
    public DateTime DateOfBirth { get; protected set; }
}

public interface IParty
{
    string Name { get; set; }
}

This will now fail as the serializer has no knowledge of the interface and the Person’s DateOfBirth property has a protected setter.

So here’s my test;

[Test]
 public void Should_Serialise_across_service_boundary()
 {
     GivenBankAccount();
     GivenAccountHasBeenSerialised();
     WhenDeserializingFromStream();

     ThenAllPropertiesShouldBeSet();
  }

I like to refactor my test code into methods to reduce noise and increase the intent on the code.  this makes it easier to understand them later. The Givens sets up the scenario I am testing;

private void GivenBankAccount()
{
    account = Builder<BancAccount>.CreateNew().Build();
    person = Builder<Person>.CreateNew().Build();
    account.Owner = person;
}
private void GivenAccountHasBeenSerialised()
{
    storeStream = new MemoryStream();
    serializer = new DataContractSerializer(typeof(BankAccount));
    serializer.WriteObject(storeStream, account);
}

The When..() method deserializes the stream back into a BankAccount instance;

private void WhenDeserializingFromStream()
{
    storeStream.Position = 0;
    savedAccountDetails = this.serializer.ReadObject(storeStream) as BankAccount;
}

And finally, we test the deserialized object’s properties are the same as the original;

private void ThenAllPropertiesShouldBeSet()
{
    savedAccountDetails.ShouldNotBe(null); 
    savedAccountDetails.SortCode.ShouldBe(account.SortCode); 
    savedAccountDetails.AccountNumber.ShouldBe(account.AccountNumber); 
    savedAccountDetails.Owner.Name.ShouldBe(person.Name
    ((Person)savedAccountDetails.Owner).DateOfBirth.ShouldBe(person.DateOfBirth);

}

This test will pick up both problems; the DateOfBirth property won’t be set correctly and the serializer will prompt to add the [KnownType(typeof(Person))] attribute to the BankAccount class;

To aid re-use and reduce code clutter I’ve created some extension methods to serialize and de-serialize objects;

public static class SerialisationExtensions
{
    public static Stream Serialize(this T target)
    {
        Stream storeStream = new MemoryStream();
        var serializer = new DataContractSerializer(typeof(T));
        serializer.WriteObject(storeStream, target);
        return storeStream;
    }

    public static T DeSerialize<T>(this Stream fromStream) where T: class
    {
        fromStream.Position = 0;
        var serializer = new DataContractSerializer(typeof(T));
        return serializer.ReadObject(fromStream) as T;
    }
}

This reduces code duplication in my tests. The below methods;

private void GivenAccountHasBeenSerialised()
{
    storeStream = new MemoryStream();
    serializer = new DataContractSerializer(typeof(BankAccount));
    serializer.WriteObject(storeStream, account);
} 

private void WhenDeserializingFromStream()
{
    storeStream.Position = 0;
    savedAccountDetails = this.serializer.ReadObject(storeStream) as BankAccount;
}

are replaced with these;

private void GivenAccountHasBeenSerialised()
{
   storeStream = account.Serialize();
}

private void WhenDeserializingFromStream()
{
    savedAccountDetails = storeStream.DeSerialize<BancAccount>();
}

This makes these methods redundant and we could move this code back into the test.

What we learnt

Creating a comprehensive suite of integration and acceptance tests did prevent our team deploying broken software. However, these were slow running tests and slowed us down.

Finding a way of moving these tests from integration to unit tests enabled us to be faster by reducing our feedback loop.

I’ve still got some more work to do on testing serialization but this method is easier to understand and more reliable than testing that attributes exist on your classes.

Reading Xml files

On a recent project we needed to read data from a file. We couldn’t simply de-serialize using the built in .net serialization as the file format had already been defined and we didn’t have the time to write custom serialization. So our problem was that given an xml file format such as the one below, how best to consume it?

<Products>
<Product name="Name1" manufacturer="Manufacturer1"/>
<Product  name="Name2" manufacturer=""Manufacturer2"/>
</Products>

This had been solved in a few places by using an xml parser. I didn’t like this as it seemed fragile.

Auto generate classes

After some thought I realised we could create the classes from the xml using the xml schema definition tool. First create an xml schema from the visual studio command prompt using xsd.exe;

xsd.exe products.xml

Then we create the classes from the schema;

xsd.exe /classes products.xsd

Deserialize files into objects

We now have the classes required to de-serialize the file into .net objects.  The below code and utility class can now handle the de-serialization;

[Test]
public void Should_load_products()
{
     var p = new XmlEntityReader<Products>();
     var productList = p.Read("blog\\productdata.xml");

     productList.Items.Length.ShouldBe(2);
}

public class XmlEntityReader<T> where T : class
{
    public T Read(string storeFullPath)
    {
       return Read(new FileStream(storeFullPath, FileMode.Open));
    }

    public T Read(Stream storeStream)
    {  
        storeStream.Position = 0;
        T settings;
        var serializer = new XmlSerializer(typeof(T));
        using (TextReader tr = new StreamReader(storeStream))
        {
           settings = serializer.Deserialize(tr) as T;
           tr.Close();
        }
        return settings;
    }
}

 

Testing serialization

A common problem I see is broken integration tests because objects can’t be serialised across service boundaries. It’s easy to forget to decorate a class or property with the DataContract attribute.

Catching this during integration tests can lead to large slow running test suites and wasted time troubleshooting, as it is rarely obvious what has the issue is.

One goal of continuous integration is to catch errors as early in the process as possible and it turns out this can be caught during unit tests.

It’s simple to add unit tests to ensure a class or property is decorated with the correct attribute;

[Test]     
public void DataMembersSetAsExpected()   
  {            
       var type = typeof(BankAccount);           
       Assert.That(type.IsDefined(
            typeof(System.Runtime.Serialization.DataContractAttribute), true));
       CheckForDataMemberAttribute(type, "SortCode"); 
  }
  private static void CheckForDataMemberAttribute(Type type, string property)
      {
          var idProperty = type.GetProperty(property);
          Assert.That(idProperty.IsDefined(
             typeof (System.Runtime.Serialization.DataMemberAttribute), true));
        }
    }

The main problem with this implementation is developers need to remember to update the test when a new property is added or removed.

It would be simple to refactor this to check all properties on a class using reflection.

However, this isn’t ideal as it will lead to false negatives as properties that won’t be serialised are still checked.

The approach I’ve adopted is to use the DataContractSerialiser to test if an object can serialised;

    [Test]
    public void Should_Serialise_across_service_boundary()
    {
        var s = new DataContractSerializer(typeof(BankAccount));
        var account = new BankAccount() { Owner = new Person() };
        s.WriteObject(new MemoryStream(), account);
    }

This has the advantage that it will only test properties that will be serialised and developers don’t have to remember to change the test when adding or removing properties.

Conclusion

Testing objects can be serialised in integration tests results in slow test suites and fails to catch the defect as early as possible.

One approach to unit testing serialisation is to verify classes have been decorated with the DataContract and DataMember attributes.

However, this leads to false positives when developers forget to refactor tests when adding properties.

The approach I am currently using it to use the DataContractSerialiser class to ensure a class instance can be successfully serialised.

Re-using workflow definitions

In the last post I showed how to define a workflow;

var workflow = Workflow<CustomerState>.Definition()
  .Configure()
  .On<Exception>(() => Console.WriteLine("Caught an exception"))
  .When<CustomerState>()
  .Do<PlaceOrder>()
  .Do<PayForCoffee>()
  .Do<PickUp>();

Although this is fine for defining small workflows, this would be cumbersome for more complex workflows.

The frameworks AsAWorkflow<T> abstract class solves this problem.  All we have to do is create a derived class and copy the above code into the Configure() method;

public class CoffeeCustomerService : AsAWorkflow<CustomerState>
{
    // Obsolete contructor
    public CoffeeCustomerService(IDefine<CustomerState> workflow) : base(workflow)
    {
    }

    // Obsolete method
    public override void Configure(IDefine<CustomerState> workflow)
    {
    }

    public override IWorkflow<CustomerState> Configure()
    {
        return Workflow<CustomerState>.Definition()
          .Configure()
            .On<Exception>(() => Console.WriteLine("Caught an exception"))
            .When<CustomerState>()
            .Do<PlaceOrder>()
            .Do<PayForCoffee>()
            .Do<PickUp>();
     }
}

The constructor and parameterised Configure method are obsolete and will be removed in a future release.  The workflow is defined in the Configure() method as usual.

All the client has to do is instantiate this class and pass the initial state to the start method;

var coffeeCustomerWorkflow = new CoffeeCustomerService(new Workflow<CustomerState>());
var customerState = new CustomerState();
coffeeCustomerWorkflow.Start(customerState);

This is a bit tidier and more re-useable.

The next minor release will have a default constructor for this class as we plan to obsolete the parameterized constructor.

Simple workflows

It’s simple to define workflows declaratively;

var customerWorkflow = Workflow<CustomerState>.Definition()
    .Configure()
    .On<Exception>(() => Console.WriteLine("Caught an exception"))
    .When<CustomerState>()
    .Do<PlaceOrder>()
    .Do<PayForCoffee>()
    .Do<PickUp>();

The above workflow defines the ubiquitous Starbucks example.  The customer states are defined by the below class;

public class CustomerState 
{     
public bool OrderPlaced { get; set; }     
public bool Paid { get; set; }     
public bool DrinkReceived { get; set; }
}

Now the workflow steps can be defined as Operations on CustomerState;

public class PlaceOrder : BasicOperation<CustomerState>
{
    public override CustomerState Execute(CustomerState data)
    {
        Console.WriteLine("Place order;");
        data.OrderPlaced = true;
        return data;
    }
}

When starting the workflow the parameterised start method should be used;

var endState = customerWorkflow.Start(new CustomerState());

Now in nuget

The latest version can be installed via the NuGet gallery. In the Visual Studio package console window;

Install-Package objectflow.core -pre