Search
Close this search box.

Object Mother Pattern versus Test Data Builder Pattern

When creating my unit tests, I’ve been a big believer in the Object Mother pattern for creating state for my immutable value objects.  Basically, I need to put the objects in a valid state in the constructor.  Doing such is usually a pain, however.  Before the ObjectMother pattern, you had code similar to this to create an object in valid state, such as a medical claim.   Remember that we need hundreds of these to capture the variations in our model for our tests.

Claim claim = new Claim(
     new DateTime(2008, 1, 1),
     new Provider("Robert", "Jones",
          new Address("1800 28th St, NW", "Washington", "DC")),
     new Recipient("James", "Smith",
          new Address("1210 14th St, SE", "Washington", "DC")),
     new ClaimLineCollection(
          new ClaimLine("00308-1")));

Object Mother

As you can see, quite a mouthful for just one object in the correct state.  Instead, we could just mask it behind the Object Mother approach.  If you’re unaware what the Object Mother pattern is, below is the basic idea.

Object Mother starts with the factory pattern, by delivering prefabricated test-ready objects via a simple method call. It moves beyond the realm of the factory by

  1. facilitating the customization of created objects,
  2. providing methods to update the objects during the tests, and
  3. if necessary, deleting the object from the database at the completion of the test.

So, let’s come up with an example of this for our problem up above:

Claim claim = ClaimObjectMother.CreateFootSurgeryClaim();

And we would encapsulate the code from above to pass in the appropriate values to that.  But, soon, you’ll find that your Object Mother is becoming a God-class and becoming cluttered with every variation that we can for unit testing the claims in our domain.  This can add up to a lot.

Test Data Builder

So, what are the alternate approaches?  What about a Test Data Builder?  And what is it anyways?  Well, it’s just an extension of the Builder Pattern to create our test objects for testing our domain.  I got the inspiration after reading a post from Carel Lotz a while back.  Although he insists it’s more of a DSL instead of the Builder Pattern.  And as you can note, this approach was combined with the Object Mother instead of using this as a complete alternate.

Let’s take a look at an example of this:

public class ClaimBuilder {
  private DateTime claimDate;
  private Provider provider = ProviderBuilder.StartRecording().Build();
  private Recipient recipient = RecipientBuilder.StartRecording().Build();
  private ClaimLineCollection claimLines =
      ClaimLinesBuilder.StartRecording.Build();

  public static ClaimBuilder StartRecording() {
    return new ClaimBuilder();
  }

  public ClaimBuilder WithClaimDate(DateTime claimDate) {
    this.claimDate = claimDate;
    return this;
  }

  public ClaimBuilder WithProvider(Provider provider) {
    this.provider = provider;
    return this;
  }

  public ClaimBuilder WithRecipient(Recipient recipient) {
    this.recipient = recipient;
    return this;
  }

  public ClaimBuilder WithClaimLines(ClaimLineCollection claimLines) {
    this.claimLines = claimLines;
    return this;
  }

  public Claim Build() {
    return new Claim(claimDate, provider, recipient, claimLines);
  }
}

As you can see, the implementation of a Builder pattern is rather easy.  But, how easy is it to implement our test cases?

Claim claim = ClaimBuilder.StartRecording()
     .WithClaimDate(new DateTime(2008, 1, 1))
     .WithProvider(ProviderBuilder.StartRecording()
          .WithName("Robert", "Jones")
          .WithAddress(AddressBuilder.StartRecording()
               .WithStreetAddress("1800 28th St, NW")
               .WithCity("Washington")
               .WithState("DC")
               .Build())
           .Build())
      .Build())
     .WithRecipient(RecipientBuilder.StartRecording()
          .WithName(James", "Smith")
          .WithAddress(AddressBuilder.StartRecording()
               .WithStreetAddress("1210 14th St, SE",)
               .WithCity("Washington")
               .WithState("DC")
               .Build())
           .Build())
      .Build())
     .WithClaimLines(ClaimLinesBuilder.StartRecording()
          .WithClaim("00308-1")
          .Build())
     .Build());

Conclusion

You can shorten things up a bit with these builders to not be as verbose as I am right here.  I could not care about certain parts of my domain when building these objects and choose to fill in only things I need to in order to my tests to pass.  Overall, I think this helps the readability of the test data that I am using.  What’s really powerful is having builders interact with other builders to create complete test cases for our domain.  I think I’m leaning towards this for my Entity objects as well.  I’ll continue looking at this and trying to tweak it a bit.

This article is part of the GWB Archives. Original Author: Matthew Podwysocki

Related Posts