Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

ObjectMother and TestDataBuilder

On our current project we have decided to drop the ObjectMother pattern in favor of using TestDataBuilder.I picked up on TestDataBuilders from Colin’s blog, though I note that our own Matthew had a post on them on an older blog too.

Object Mothers 

When we write our tests we often want to highlight the variables that are important to the test outcome i.e. this pre-condition state leads to this post-condition state. Other parts of setup however can obscure our test, so we tend to want to put into a creational method or setup. For example if it is important that my customer is in Washington I might write something like:

Customer customer = CreateTestCustomer();

customer.State = new State(“WA”);

When you push down this route you can find that you need a CreateTestCustomer on a number of test fixtures. This is especially true if you prefer a state based approach to testing. The idea behind Object Mother is that instead of these local creation methods we create a factory that we can dispense test objects from. This allows us to re-use the creation code, and prevents duplication, which feels like a good thing.

Customer customer = CustomerObjectMother.CreateCustomer();

customer.State = new State(“WA”);

Why did we stop using object mother?

We hit a slew of issues with object mother. The problem is what happens after the first person writes a mother for an object. Subsequent consumers do not always want to use the object with exactly that state. Either the data in insufficent or not what is needed for their test. The solution to this should be to either add another creational method:

Customer customer = CustomerObjectMother.CreateWashingtonBasedCustomer();

or to modify the object returned by the mother to the correct state.

Customer customer = CustomerObjectMother.CreateCustomer();

customer.State = new State(“WA”);

The latter is the better approach, because you usually need a variation because your test depends upon the returned object having a specific state. That is information that you should really encode into the test itself for clarity. If the reader cannot pick out the variables that affect the outcome of your tests from reading the test method itself, and have to go to other methods to understand that test, it increases the friction the reader experiences in understanding the sysem under test (SUT). In addition if we fall into the trap of depending on the state of the object returned by the mother, we end up with a shared fixture which makes our tests fragile. If someone changes the state of the object to something required for their test, then other tests may break. This is the classic fragile test problem that using a shared fixture leads us too.

So we wanted something that would encourage correct usage: modify the default object to explicity show the values that affect the outcome of the test.

TestDataBuilders

The basic idea behind a data builder is that we can quickly dispense constructed objects for use with tests by writing code like the following:

 var product = new ProductBuilder().Build();

This should give you a object suitable for use in testing. Once again, you do not want to depend on the values in the properties of the object that we build. If your test does not care what the state of the object is, then you can just use the object returned by the vanilla build. If you do need the returned object to have a specific state you have two options. The first is to set the value explicitly. So if you wanted nto set the product code explicitly on your product you could write something like the following:

var product = new ProductBuilder().Build();

product.ProductCode = new ProductCode(“CAG”);

So far no there is no real difference. We could always do this from Object Mother. What we wanted was encouragement to set these values explicitly. With TestDataBuilder we support this by providing overrides for the properties that the builder sets. Conventions is to name these WithXXXXX, where XXXX is the property you want to set the value of, when the builder creates its object. We make these WithXXXX methods return the builder so that they
can be chained.

We want our test code to look something like:

var product = new ProductBuilder()

    .WithProductCode(new ProductCode(“CAG”))

    .Build();

 The code for this might like something like this:

public class ProductBuilder

{

    private ProductCode productCode = new ProductCode(“DAB”)  ;

    private String productName = “My Widget”

  

    public Product Build()

   {

          return new Product

          {

                  Code = productCode,

                  Name = productName

          } ;

   }

 

    public ProductBuilder WithProductCode(ProductCode newCode)

    {

         productCode = newCode;

         return this;

    }

    public ProductBuilder WithProductName(string newProductName)

    {

       productName = newProductName;

       return this;

    }

}

I would suggest providing a WithXXXXX for every property that you set by default in the builder. This makes it clear that you can override the default construction. The fluent interface syntax makes our intent very readable – the WithXXXX values are important to the test and will influence the outcome. There is no outcome difference between creating an object from a mother, and modifying its values, and using a builder and modifying its values. However, IMO, the builder syntax is easier to comprehend and thus more maintainable.

Either way the result is that a) we remove the dependency of our test on the values set in the builder – if we care about what they are we set them explicitly b) we highlight the values that are important to our test – by virtue of the fact that we set them we are saying that they effect what we is under test. Of course the builder pattern makes this easier, but, as usual, is not a silver bullet. You still have to remember that depending on the state of the vanilla build is fragile.

In addition TestDataBuilder helps when the you want to build Value Objects instead of Entities. Because Value Objects are usually immutable you cannot modify them once they are constructed. Because we cannot intercept the creation with Object Mother the only way to modify the dispensed object is to re-create the whole Value Object within your test.  Because TestDataBuilder lets us set the properties that will be used at object creation, we can just supply the desired state to the builder so that it is created as required.

Where we have a complex dependency, one that might for example benefit from its own builder, I tend to include them as a WithXXXXXX so that you only have to add them if you need to use them to build your object. I have seen some people use a builder silently within another builder for their vanilla object. I am cautious on this as it could lead to nasty circular dependencies between your builders. The point is to have a simple vanilla build so that we do not have to buy complexity unless we need it.

If you make a second call to a builder you will get an exact copy of the object. This may be what you want, but it might not be as you might expect some values to be reinitialized, for example random names or id values. In that case create a new builder each time rather than re-using them.

 

About Ian Cooper

Ian Cooper has over 18 years of experience delivering Microsoft platform solutions in government, healthcare, and finance. During that time he has worked for the DTi, Reuters, Sungard, Misys and Beazley delivering everything from bespoke enterpise solutions to 'shrink-wrapped' products to thousands of customers. Ian is a passionate exponent of the benefits of OO and Agile. He is test-infected and contagious. When he is not writing C# code he is also the and founder of the London .NET user group. http://www.dnug.org.uk
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Lawrence

    When you test it is my opinion you should never use static test objects! You should use RandomStringUtils and the like because when you make an error in your test case by comparing the wrong objects, the test may pass due to all values being the same. The builder pattern is in my opinion less clear and heavier to create than the mother. I know I am solo here but I see more disadvantages in builders then advantages.

  • http://shouldbeableto.wordpress.com/2009/02/01/3/ Gareth

    Hi Ian

    I’ve written something recently for generating test objects generically.

    It follows the test data builder pattern you describe here, and uses With(x => x.Title = “value”) methods.

    For lists there is a slightly different syntax – CreateListOfSize(100).WhereTheFirst(20).Have(x => x.Title = “value”);

    It’s only really a proof of concept at the moment but I’m going to use it in projects I’m working on and develop it as I go along.

    I’ve blogged about it here:

    http://shouldbeableto.wordpress.com/2009/02/01/3/

    I’d appreciate any comments or suggestions.

    Kind regards

    Gareth

  • Manoj Waikar

    Hi Ian,

    Thanks for the article. I understood the difference between an ObjectMother and a TestDataBuilder. Now, although we call it a TestDataBuilder, but in effect, it builds domain entities and / or value objects. So my doubt is -> should we have this TestDataBuilder in –

    1) The same assembly as the domain model classes (so that these builders are usable from other code to fluently build domain objects)

    2) The assembly containing unit test code, so that their use is strictly limited to testing code (I am assuming that typically we’ve a separate assembly containing testing code)

    3) In some third assembly, so that one is free to use it any way he likes?

    Please throw some light on this issue. Thanks in advance.

    Regards,
    Manoj.

  • http://elegantcode.com Jan Van Ryswyck

    I’m not a huge fan of casting operators either, but I do like the syntactical advantage it gives for calling Withxxx methods for other entities/value objects:

    var product = new ProductBuilder()
    .WithProductCode(new ProductCodeBuilder
    .WithValue(“CAG”));

    It saves two calls to the .Build() method.

    http://elegantcode.com/2008/04/26/test-data-builders-refined/

  • http://blogs.manicprogrammer.com/heynemann Bernardo Heynemann

    We’re using the second approach, but we call them Fixtures, so for instance:

    CustomerFixture.InMemory.WithName(“Some Customer”).Create();

    Some major concepts here:
    1) InMemory vs InDatabase – Those are very important when you need to do functional/integration testing.
    2) The methods that set property values must start with “With”.
    3) Create is where the instance is actually created.
    4) All defaults should be set to you, so if you do:
    CustomerFixture.InMemory.Create();
    IT MUST WORK!
    This last one also applies to dependencies. So if a customer needs a country and you don’t specify one using WithCountry, then the Fixture must create one.

    Now that I explained how we’re doing it, I have a project in Stormwind (http://www.stormwindproject.org) called PowerFixtures that aims at being a generic way of doing that. You can check it out at http://svn.stormwindproject.org/svn/Stormwind.PowerFixtures/.

    If you’re interested in it, check the test cases. They are pretty self-explanative.

    Cheers,
    Bernardo Heynemann

  • Ian Cooper

    @Victor

    I used to do a lot of this back when I was a C++ programmer. We used to write a lot of code that exploited language features in clever ways and fell in love with the Loki library.

    The trouble was that such code often fell foul of the principle of least suprise – it was not obvious to a reader how you achieved the desired effect.

    So I’m cautious around overloading a casting operator, because am I really casting? it may be close enough to be comprehensible.

    But that may just be my taste.

  • http://victorkornov.ru Victor Kornov

    Instead of a final .Build() method you can you C#’s implicit cast operators like so:
    public static operator Order(OrderBuilder builder)
    {
    return … ;
    }

  • Stephen

    I’ve noticed this, is there not a test framework that allows you to take your test dependencies as parameters? you could annotate test classes / methods to effect the variation of those dependencies.

  • http://marcostuder.blogspot.com/ Marco Studer

    We use both ObjectMother and Test Data Builder to create our test objects. Since C# 3.0 we use Object Initializers for the most cases and only use the patterns above if the creation logic is complex and shared among fixtures.

    I really like the fluent interface of your Test Data Builder.

  • Ian Cooper

    @Carl

    I’m sure we are not the only ones. Once you see the builders solution it becomes a bit of a no brainer.

  • http://www.arnesten.com Carl Arnesten

    It was fun reading this as we at our company have walked the same path :)
    First using what you call ObjectMother (we didn’t call it ObjectMother, but it was a static class with factory methods). Then we recognized that the tests became hard to read and the ObjectMother hard to maintain when making changes. So we also switched to builders.