As you start to get better at creating well formed objects, that are immutable or protect their own invariants, constructing the necessary fixtures for your tests can become quite repetitive and our test arrangement can start to get unwieldy. The first bit of refactoring we might do to improve things could be to extract creation methods, but this doesn't scale so well beyond a single test file.

One of the many things I picked up from the Growing Object Oriented Software book was the use of Object Mothers.

Object Mothers are a kind of factory, producing canned test fixtures for use directly in your tests, or to help constructing other test fixtures. They help to remove duplication and make it easy to create complex fixtures.

class ExampleEmployees
{
    public static function activeEmployee()
    {
        return Employee(
            EmployeeId::generate(),
            new Name("Jack Burton"),
            ExampleEmploymentHistory::emptyHistory()
        );
    }
}

Once created, they can be used in a number of tests and really help to keep your tests concise.

/** @test */
public function it_allows_active_employees_to_login()
{
    $employee = ExampleEmployees::activeEmployee();

    $spec = new IsAllowedToLogin();

    $this->assertTrue($spec->isSatisfiedBy($employee));
}

When they're working well, Object Mothers are very simple and very effective. I use them daily and you should definitely try them out, but be wary, they can quickly become quite cumbersome.

class ExampleEmployees
{
    public static function newStarter()
    {
        return new Employee(
            EmployeeId::generate(),
            new Name("Jack Burton"),
            ExampleEmploymentHistory::emptyHistory()
        );
    }

    public static function seasonedDeveloper()
    {
        return new Employee(
            EmployeeId::generate(),
            new Name("Gracie Law"),
            ExampleEmploymentHistory::fromJuniorToSeniorDeveloper()
        );
    }
}

This example shows quite a few traits of Object Mothers. The first thing to know about Object Mothers is that tests can and therefore will depend on some of the canned values contained within the objects.

Take the following two tests, at the first glance they look really neat and tidy, and will have been pretty easy to write. Looking more closely, without seeing the production code, we'd have to assume that the seasonedDeveloper's employment history, contains the necessary experience that the IsSuitableForFireSafetyOffice specification requires. This could be as simple as years in service, or it could be as complex as having experience in particular positions. Unlike our first example that explictly showed we were creating an active employee, and testing that an active employee could login, our specifics are a little more vague here.

/** @test */
public function it_rejects_less_experienced_employees()
{
    $spec = new IsSuitableForFireSafetyOfficer();

    $this->assertTrue($spec->isSatisfiedBy(ExampleEmployees::newStarter()));
}

/** @test */
public function it_accepts_experienced_employees()
{
    $spec = new IsSuitableForFireSafetyOfficer();
    $this->assertTrue($spec->isSatisfiedBy(ExampleEmployees::seasonedDeveloper()));
}

I'm not keen on the coupling this brings. Even though our object mother methods contain the words new and seasoned, so do communicate some notion of experience, they aren't precise enough for me. Ian Cooper describes this coupling as a form of Shared Fixture, in that a developer changing the value for one of the examples for a particular test, could break another test somewhere else that depended on the same value, meaning we have fragile tests.

The fact that the Object Mothers become a global place for defining the canned objects does alleviate some of the coupling concerns, as all programmers on your team will know exactly where to look to inspect how the fixtures are created. In the Martin Fowler article, he actually mentions that some teams totally embrace this to the point where they give the example objects personas, such that the methods in the examples above might be known as Jack and Gracie, and their attributes are well known. So, it is well known within the team that Gracie (our seasonedDeveloper) has enough experience to be a fire safety office, and this attribute should not be changed, much like the active attribute of the activeEmployee example. As long as the team understand and can recall the attributes of each persona or know exactly where to look when they need to, it might not be too much of a problem, but isn't something I feel too comfortable with.

Another one of the problems with object mothers, is that the canned objects they create are just that, canned objects. As a consumer, we're restricted in the types of objects we can get from them, without adding more specific methods. Sometimes this can be a good thing, you get a fairly generic object from the Object Mother and then customise it in the test method. This helps to show a lot of intent within the test.

/** @test */
public function it_accepts_anyone_with_the_fire_safety_training()
{
    $employee = ExampleEmployees::newStarter()
        ->award(new FireSafetyTrainingCompetency());

    $spec = new IsSuitableForFireSafetyOfficer();

    $this->assertTrue($spec->isSatisfiedBy($employee));
}

The problem really arises when the change we need to make to a generic example object to be more specific, can't be done after instantiation, either because the whole object is immutable or perhaps just the part we're interested in is immutable. It's tempting to add another method to the Object Mother, to keep the complexity of creating the fixture out of the test and available for reuse in other tests.

/** @test */
public function it_accepts_anyone_who_has_previously_been_a_fire_safey_officer()
{
    $employee = ExampleEmployees::previouslyAFireSafetyOfficer();

    $spec = new IsSuitableForFireSafetyOfficer();

    $this->assertTrue($spec->isSatisfiedBy($employee));
}

As you can imagine, this can quickly get out of hand if you need a lot of different example employees. Not only will there be a lot of examples for people to be familiar with, but the code required to create many such examples can quickly become complicated. Looking back at the examples, we already have duplication, in that the activeEmployee and newStarter examples are exactly the same. We could remove the duplication by having one aliased to the other, but that brings it's own complexities. One possible option to alleviate this problem is to add options and arguments to the methods, but this is really just creating a different kind of coupling and would probably only be a quick fix for a short while, but quickly crash and burn.

This post has probably come over more negatively towards Object Mothers than I had intended, but it turns out that the downsides to Object Mothers take more explanation than the good bits. However, having read this, I do suggest you now take a look at Test Data Builders, a better alternative to Object Mothers.