Ian Cooper

Sponsors

The Lounge

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
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.


 


Posted Fri, Oct 17 2008 2:40 PM by Ian Cooper

[Advertisement]

Comments

Carl Arnesten wrote re: ObjectMother and TestDataBuilder
on Fri, Oct 17 2008 10:12 AM

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.

Ian Cooper wrote re: ObjectMother and TestDataBuilder
on Sat, Oct 18 2008 12:14 PM

@Carl

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

Marco Studer wrote re: ObjectMother and TestDataBuilder
on Sun, Oct 19 2008 5:47 AM

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.

Stephen wrote re: ObjectMother and TestDataBuilder
on Sun, Oct 19 2008 1:02 PM

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.

Victor Kornov wrote re: ObjectMother and TestDataBuilder
on Sun, Oct 19 2008 2:14 PM

Instead of a final .Build() method you can you C#'s implicit cast operators like so:

public static operator Order(OrderBuilder builder)

{

return ... ;

}

Reflective Perspective - Chris Alcock » The Morning Brew #204 wrote Reflective Perspective - Chris Alcock » The Morning Brew #204
on Mon, Oct 20 2008 2:01 AM

Pingback from  Reflective Perspective - Chris Alcock  » The Morning Brew #204

Ian Cooper wrote re: ObjectMother and TestDataBuilder
on Mon, Oct 20 2008 3:38 AM

@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.

Bernardo Heynemann wrote re: ObjectMother and TestDataBuilder
on Mon, Oct 20 2008 11:54 AM

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 (www.stormwindproject.org) called PowerFixtures that aims at being a generic way of doing that. You can check it out at svn.stormwindproject.org/.../Stormwind.PowerFixtures.

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

Cheers,

Bernardo Heynemann

Jan Van Ryswyck wrote re: ObjectMother and TestDataBuilder
on Mon, Oct 20 2008 2:28 PM

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.

elegantcode.com/.../test-data-builders-refined

2008 October 21 - Links for today « My (almost) Daily Links wrote 2008 October 21 - Links for today « My (almost) Daily Links
on Tue, Oct 21 2008 4:34 AM

Pingback from  2008 October 21 - Links for today « My (almost) Daily Links

xUnit patterns. « Life, programming etc. wrote xUnit patterns. « Life, programming etc.
on Tue, Oct 21 2008 2:09 PM

Pingback from  xUnit patterns. « Life, programming etc.

Manoj Waikar wrote re: ObjectMother and TestDataBuilder
on Wed, Dec 10 2008 11:11 AM

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.

Gareth wrote re: ObjectMother and TestDataBuilder
on Sat, Jan 31 2009 10:28 PM

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:

shouldbeableto.wordpress.com/.../3

I'd appreciate any comments or suggestions.

Kind regards

Gareth

Ian Cooper [MVP] wrote Seizing the BDD Nettle
on Tue, Mar 31 2009 8:29 AM

Learning BDD I have been trying for some time now to understand what the BDD exponents are talking about

Add a Comment

(required)  
(optional)
(required)  
Remember Me?