This page looks best with JavaScript enabled

Testing Toolbox - Convenience

 ·   ·  ☕ 4 min read

Make your live easier!

Broadly speaking, these tools are used to make things easier when testing by setting up objects/data in a reproducible and reliable manner with minimal effort.
They might take a minute to set up, but as soon as the data is needed in more than two tests you’ll be thankful you took the time.

Fixture

A test fixture is an environment, a state or a dataset we use to consistently test a piece of software.

This example used by Martin Fowler seems appropriate:

When you write tests in a reasonably sized system, you find you have to create a lot of example data.
If I want to test a sick pay calculation on an employee, I need an employee.
But this isn’t just a simple object - I’ll need the employee’s marital status, number of dependents, some employment and payroll history.
Potentially this can be a lot of objects to create.

All of that data is what we call a test Fixture, no matter where it is or what shape it has as long as it’s valid.
It could be something as simple as a json file with all the data we need.


Often enough, the term Fixture is used to also refer to the utilities we build to provide that data.
Example.

For example, say you need the data from the example above to be persisted in your testing database to see whether a given function can fetch it correctly.
You might create an EmployeeFixture with a save() function that receives an Employee and persists it.

Here the naming gets kinda muddy: Although we usually call these types of helpers Fixtures, what they actually do is provide the Fixture itself, they set up the testing environment.


Builder

A creational design pattern that lets you easily construct complex objects step by step as needed.
The pattern allows you to produce different types and representations of an object using the same construction code.

They still end up producing a (in memory) Fixture.
It’s just a more useful and flexible way of getting it.

Example

Say you want to test how your application behaves when saving a user to the database if it has a faulty email address.
You could go new User(name, age, id, email, maritalStatus, ...), but you really only care about the email for this test case.
Plus, imagine name, age and maritalStatus all go through validations, so you can’t just put whatever in those fields.
It would be nice if you could use a sort of “default valid User” and just set a faulty email to it.

Something like User myUser = new UserBuilder().withEmail('doesntWork').build() with the Builder setting the rest of the properties to some irrelevant (but valid) default for you.
Example.

Details

You’ll often want to test behavior affecting semi complex entities.

You can use the Builder pattern to your advantage by having it set some sane defaults to, in our example, the User while also allowing you to customize the Entity at will.

This also gives you a centralized standard ‘User maker’ for your tests.
So as long as this Builder accurately reflects the behavior of the production entity, you can be sure that your tests are relevant.

Plus, if something changes about your User (for example, the age now defaults to 18 if not set) you only need to apply the change in the Builder instead of parsing all the tests that use the User entity.

Object Mother

An Object Mother is a sort of fancy factory pattern, delivering prefabricated test-ready objects via a simple method call.

Again Mr. Fowler:

[…] it makes sense to have a factory object that can return standard Entities.
Maybe ‘John’, an employee who just got hired last week; ‘Heather’ and employee who’s been around for a decade.
Object Mother is just a catchy name for such a factory

Example

You might find yourself using our UserBuilder in a few different tests just to end up creating the same type of User.
What ‘type of User’ means depends on context but think of your typical Admin User, Guest User, New User, etc.

You can remove this duplication by abstracting the User creation into an Object Mother and just write testAdminUser = new UserMother.withAdminRole() or testAdminUser = new UserMother.admin() and call it a day!
Example.

Details

Object Mothers differ from Builders in that Builders usually create dummy versions of domain Entities with no specific scenario in mind while Object Mothers are meant to Build more specific and complex instantiations of your domain Entities with the necessary data.

As soon as you find yourself creating the same kind of user in two different tests, go for an Object Mother.

You’ll use it to reduce code duplication, increase test maintainability and encourage other developers to write more tests by making test objects super-easily accessible.

Support the author with