Clean Code: Test data preparation or what test data builders are good for

Today I read this blog post about how to simplify test data preparation.

The author of the blog post states that setting up test data for tests is sometimes difficult and bloats up the test code, resulting in bad readability and maintainability. I completely agree with that.

The author continues by solving this problem by loading the test data from a file and using it in the test. That minimizes the code needed to set-up the test data, but results in a disconnect between the test and the data or example used for it. Leaving us with an obscure unit test.

We solve this problem differently.

Test data builders

We use a test data builder to create the test data with minimal code inside the test.

Our test would look something like (yeah, I’m a C# developer):

public EmployeeDAOTest
{
    [Test]
    public void SavesEmployees()
    {
        // create test data
        Employee employee = new EmployeeBuilder()
            .Create()
                .WithName("testFirstName", "testLastName")
                .WithAge(19)
                .WithEmail("test@mail.com")
                .WithAddress("testLine1", "testLine2", "testLine3", "testLine4")
            .Build(); 

        // Execute the behaviour under test
        EmployeeDAO employeeDAO = new EmployeeDAO();
        bool result = employeeDAO.Save(employee);

        // Code To Assert Result
    }
}

A builder using a fluent API gives you a lot of flexibility:

  • you can leave out things that are not relevant for the test (the builder will use a default value)
  • you can provide several overloads of the API methods to exactly match the needs of the unit test
  • you can use nested builders to build complex parts of a test data object tree

The advantages of a builder compared to loading data from a file, database or resource are that

  • all data needed to execute the behaviour is visible inside the test method (and not somewhere hidden in a file or database)
  • you can use constants in the test data values that are used in the assertions, too

How to implement a test data builder

A simple test data builder as used in the example above is very easy to write:

public class EmployeeBuilder
{
    private Employee employee;

    private EmployeeBuilder()
    {
        this.employee = new Employee();
    }

    public static EmployeeBuilder Create()
    {
        return new EmployeeBuilder();
    }

    public EmployeeBuilder WithName(string firstName, string lastName)
    {
        employee.FirstName = "testFirstName";
        employee.LastName = "testLastName";

        return this;
    }

    // methods for all other properties ...

   public Employee Build()
   {
       return this.employee;
   }
}

For hierarchical builders, we introduce interfaces to tidy up the syntax of the fluent API. But for most builders, this approach is good enough.

Please let me know what you think in the comments below.

Happy coding!

About the author

Urs Enzler

2 comments

By Urs Enzler

Recent Posts