Mark Needham

Thoughts on Software Development

Coding: Putting code where people can find it

with 10 comments

I’ve previously written about the builder pattern which I think is a very useful pattern for helping to setup data.

It allows us to setup custom data when we care about a specific piece of data in a test or just use default values if we’re not bothered about a piece of data but need it to be present for our test to execute successfully.

One problem that I noticed was that despite the fact we had builders for quite a number of the classes we were using in our tests, when new tests were being added test data was still being setup by directly using the classes instead of making use of the builders which had already done the hard work for you.

A colleague and I were pairing last week and I pointed out one of these areas and he suggested that we should try and introduce the builder pattern to try and solve it!

We actually didn’t have a builder for that particular piece of data yet but I pointed out several other builders we did have which he wasn’t aware actually existed.

Clearly I hadn’t done a very good job of communicating the existence of the builders but when discussing this we realised that the turn around time for checking whether or not a builder existed was actually not very quick at all.

  • Start writing test and realise that test data setup was a bit complicated
  • At best search for ‘ClassNameBuilder’ if you knew that was the naming convention for these builders
  • Create test data for the test by typing ‘new ClassNameBuilder()…’

We therefore came up with the idea of anchoring the builders to a common class which we called ‘GetBuilderFor’.

It is now possible to create test data by writing code like this:

var car = GetBuilderFor.Car().Year("2009").Make("Audi").Build();

The nice thing about this is that we now only have to type in ‘GetBuilderFor’ and then a ‘.’ and ReSharper will show us all the builders that are available to us. If there isn’t one then we can create it.

Communication wise we’ve both been mentioning this approach in our stand ups and to other people when we pair with them and hopefully this approach will stop the duplication of test data creation.

For those in the Java world Jay Fields wrote a cool post a few months ago where he describes a way to do a similar thing in Java. I think this is one place where having static imports makes the code read really fluently.

Be Sociable, Share!

Written by Mark Needham

June 2nd, 2009 at 11:35 pm

Posted in Coding,Communication

Tagged with ,

  • Ed Blackburn

    Not a bad idea Mark. On the subject of builders, have you looked at NBuilder (http://code.google.com/p/nbuilder/) yet?

  • I was thinking that it’d be cool to write something like that! Looks like it’s already been done.

    Might have to give that a try out and see what it’s like.

    Thanks for the link.

  • Mark, I don’t know if you’ve seen Pete Yandell’s “Machinist” in the Ruby world, but it has a wonderful builder style with excellent findability as well as readability.

    You provide Machinist with blueprints on how your object might normally be constructed:

    
    Car.blueprint do
      year 2009
      manufacturer
      model
      description { Sham.description }
    end
    

    Then, you can ask Machinist to build an object and only be as specific as you need to for your test:

    
    regular_car = Car.make
    old_car = Car.make(:year => 1970)
    old_audi = Car.make(:year => 1970, :manufacturer => audi)
    nondescript_car = Car.make(:description => nil)
    

    The blueprints are completely findable because they are (by convention) kept in one file, and the “make” method is on the domain class itself (just like “new” and “create”).

  • Hello Mark.

    This pattern certainly has its uses. On the other hand, sometimes it might be a dependency problem: you cannot depend on the GetBuilderFor class without depending on all classes it has builders for.

    Another trick is to make the builder an inner class of the class it is building. If the static method for accessing the builder is named “with”, the building sentence becomes:

    Car car = Car.with().model(“Model”).year(2009).build();

    (from http://web.sysart.fi/developer/articles:nested_fluent_builder)

  • @Ville Good point I hadn’t thought about the depedency problem although with the approach that you suggest wouldn’t that mean that the builder ships with your production code?

  • Nathaniel Neitzke

    Ville,
    Not necessarily true if the methods such as Car() in GetBuilderFor.Car() are extension methods, which I believe is the way Mark intended.

  • Mark, yes I ship the builder with all other production code.

    It seems most people use builders only as testing tools, but why keep all nice things in test-code only? Object creation is needed in production code, too.

    Especially, if you care to read the observations in the article I mentioned, fluent builders are very useful streaming tools and make the data flow (possibly through transformers) in a maintainable and efficient way.

  • Ed Blackburn

    Nathaniel / Mark,

    As you can’t return ‘this’. How would you implement your builders as static ext methods?

  • Pingback: Builders hanging off class vs Builders in same namespace at Mark Needham()

  • Christer Nyberg

    Ed,

    You can simply return the first parameter of the extension method. (The this parameter.)