Building Unit Test Data

Unit tests have most value when they’re easy to read and understand. Unit tests typically follow a very straightforward pattern:

  1. Simulate system state
  2. Call the method under test
  3. Verify the method’s result and side effects

So long as this pattern is obvious in the test, the test is readable.

Three or four line test methods are succinct, focussed and readable. However, simulating the system state often requires creation of complicated stub objects. This can result in long test methods where most of the test is setup followed by one or two lines of verification.

Factoring out object creation

Where possible, it’s best to factor out any hard setup work into separate methods. If it’s not possible to create the necessary stub data in one or two lines, make a private helper method just to create the stub data.

BEFORE:

AFTER:

This makes simpler test methods but may result in a glut of private helper methods to create every conceivable variation of test data.

Builder Pattern

In theĀ  book Growing Object-Oriented Software, Guided by Tests, authors Steve Freeman and Nat Pryce suggest a neat pattern for cleanly creating test data for unit tests. They suggest using the builder pattern to build test objects which are as simple or as complicated as necessary for the test. The builder can set default data in fields meaning that only data significant to the result of the test needs to be set.

Notice that the setter methods return this. This allows method chaining. So we can now create our zero sized test spanner like so:

When we use the SpannerBuilder, we don’t need to worry about setting an id, name or owner for the Spanner. If we don’t define an attribute, the spanner will use its default.

Improving readability

We can make a couple of improvements to the syntax of the builder to make it more like a domain specific language (DSL). First, create one or more static factory methods to create the builder instance rather than using the new keyword to create the builder instance. Second, change ‘setter’ method names to words that make the chained calls read more like an English sentence. Like this:

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *