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.