Wednesday, August 13, 2008

Test Data Builder and Object Mother

I've been meaning to write about this topic for a while because I think correct use of these two patterns can make a big difference to tests for any moderately complex domain model.

I'm not going to discuss the details of the two patterns themselves because there's already a lot of good content out there about them (see links at end), instead I'll discuss my impressions of them.

Why Are They Needed?

For any moderately complex domain model you're going to have quite a few ENTITIES and VALUE OBJECTs and although you'd like to avoid a Web of associations you will have associations between them.

Thus when testing a Customer (ENTITY) its quite possible that you'll want to associate an Account (ENTITY) or Name (VALUE OBJECT) with it. However you don't necessarily want the creation/configuration of the Account/Name inside the test fixture:

  1. You probably want to reuse the creation code in other tests.
  2. You don't want the creation code adding complexity to the tests, complexity that the reader doesn't care about.

There are other reasons they can be useful, most of which relate to any type of Test Helper.

Application

So far my approach has been to use TEST DATA BUILDER for value objects and then OBJECT MOTHER for Entities.

VALUE OBJECTS validate in their constructor so if you try to use an OBJECT MOTHER you get a lot of methods and overloads. For example you'd have methods to create an Address with a specific Postcode, another to create it with a specific PostCode and town...it gets old very fast and that's why I think an EXPRESSION BUILDER based approach is preferable.

ENTITIES do not necessarily force you to provide all the data to them in the constructor so an OBJECT MOTHER is a good approach. I use a combination of the patterns described in the Creation Method article in the XUnit Patterns page (also see Test Helper page on same site). This works nicely because you can use a simple method on the OBJECT MOTHER to create an ENTITY (give me an active customer) and can then customize the returned Customer in the test method (for example by giving them a rejected order).

I have used TEST DATA BUILDER for ENTITIES too, in addition to OBJECT MOTHERs, however I've only done this a few times and they are quite specific. In particular these are very high level builders so they handle cases like "Give me a customer with a relationship to an account manager who works for the company Spondooliks". This case involves at least three AGGREGATES and the associations between those aggregates and we want to make that setup really readable, which either means putting it in a method in the test class or using a TEST DATA BUILDER (or both).

One thing to be careful of is relying on values of objects returned by OBJECT MOTHERs or TEST DATA BUILDERS. If you don't pass in a value and it isn't implied by the name of the members that you used then do not rely on the value in your tests because if you do they become overly fragile and complex. So if you call CreateActive on an CustomerObjectMother and don't pass in any data then its safe to assume that the returned Customer is Active but you cannot assume that the Customer has an Age of 28 (see Creation Methods).

Are They Evil?

Some argue that both patterns are evil because by creating real ENTITIES/VALUE OBJECTS you are going from writing unit tests to writing small integration tests. I'm more in agreement with Ian Cooper on this point and think its usually fine to use real domain objects in tests (within reason). However if you disagree then you can go ahead and mock out your ENTITIES but you'd still want to use TEST DATA BUILDER for your VALUE OBJECTS (see this test smell from the mockobjects guys).

We want to avoid using OBJECT MOTHER to hide design smells For example if our ENTITIES and AGGREGATEs are too large, too complex, are overly coupled, or have too many states then we could use an OBJECT MOTHER to hide the fact that these problems make the objects difficult to create. Eric Evans discussed this topic here and I handle it by trying to ensure that the OBJECT MOTHERs themselves are kept clean and simple, if they get complex I definitely consider that as a good indicate that there is something wrong with the design.

Another argument which I've heard is that OBJECT MOTHERs and BUILDERs add a lot more code to step through and make debugging tests more difficult. As it happens I rarely debug tests but if I did I either wouldn't step into the OBJECT MOTHER or BUILDER or I'd add the necessary attributes (as Greg Young does).

Object Mother Links

  1. Pattern - You can also get this PDF here.
  2. Martin Fowler
  3. Ward's Wiki
  4. Creation Methods

Test Data Builder Links

  1. Nat Pryce - Great series of articles on the pattern.
  2. Expression Builder

Several other people use slightly different approaches, for example this one is quite interesting and is a variation of the approach I've settled on.

Share This - Digg It Save to del.icio.us Stumble It! Kick It DZone

2 comments:

  1. The one thing I like the most about applying Test Data Builder/Object Mother is the decoupling of my tests from the classes in the domain model. I must admit though that I mostly apply the Test Data Builder pattern for both Value objects as Entities.

    ReplyDelete
  2. Please take a look at NBuilder:

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

    ReplyDelete