Untangling test setup

Where we learn about some patterns that will help separate test setup from tests, making tests easier to read and understand.

It is quite common that we manage to tangle our test data setup in our tests. There are a number of reasons to why it’s good to untangle it. To list a few:

  • Tests being the living documentation of how to use your code, it’s important to ensure it communicates intent. Removing tangles of test setup from that story makes it easier to express what’s important.
  • Extracting complicated setup from the test code also limits the blast area impact of refactoring both our code and our test code.

When we work with this there are a couple of different patterns we can use, depending on context and preference. For more complex setup, and especially when working with BDD, Screenplay is recommended. But for smaller SUTs that’s a bit of an overkill. When working with micro tests I’d recommend using Test Data Builder or Creation Method. Both patterns are described below. But before that I’ll talk a bit about what, in my experience, drives the choice.

When I start to write the tests I usually start doing setup using the pattern Inline Setup. I.E. I write the setup in the test method. It’s easy and quick. If the resulting test is expressive enough I’ll leave it there.

Most of the time the test isn’t expressive enough though. It’s not uncommon that our domain objects have values we don’t care about in a single test, but we still need to provide them to construct the objects. That’s OK, it’s how we ensure we have domain objects with a high level of integrity. But it does make our Inline Setup messy.

So from here I usually extract the setup code into Creation Method. It’s a simple, descriptive method that allows me to vary what’s under test and default everything else. And I can use its name to aid the narrative I create for the SUT I’m testing.

This is sometimes enough. If I don’t do any more testing on the domain object in other test classes I usually stop here. No point in creating more things than absolutely needed (see Four rules of simple design).

But, when I hit the point where I need to do this setup in more than one place, for example in two different test classes (or files or what is your way of co-locating what goes together) I refactor my Creation Methods into Test Data Builders.

Creation Method

This pattern is described in the xUnit Patterns book.

This pattern is used when we duplicate setup of an object in several places in our test. The method name should describe the kind of object it returns, in a way that helps the reader of the test understand what’s important in our setup and what is not. Often (not always) we pass in the one or two things that varies between our tests when setting up the SUT. The stuff we then use in our verification of behaviour. See more details in the link above.

Test Data Builder

This is basically a build patter, but it is created to aid our description of how a SUT is used, I.E. it is used as a linguistic aid in our tests. Nat Pryce describes it well in his blog.

The key things here are:

  • This is a new class, so a new element. Therefore, it does increase complexity. But it also lowers test coupling when we need to create an object in more than one place.
  • It is very important that the builder is written to simplify description of how the SUT is created. Increasing the value of the documentation of the SUT in your tests. If it doesn’t do this it can quickly become a confusing mess of indirection instead of an aid.