Design Patterns: The builder pattern

The builder pattern is the first design pattern I intend to write about during the next weeks. Design patterns as introduced by the GoF (gang of four) are, in its essence, solutions to software design problems. I have some favorite design patterns that I tend to use many times during my projects, and the builder pattern is one of them.

Although I use the builder pattern in development code, I tend to use it more in my unit tests. To demonstrate the advantages of using the builder pattern in unit tests lets explain them with a classic example:

public class Person
{
    public Person(string firstname, string lastname, DateTime birthdate, string gender)
    {
        this.FirstName = firstname;
        this.LastName = lastname;
        this.BirthDate = birthdate;
 this.Gender = gender;
    }
    public string FirstName { get; private set; }
    public string LastName { get; private set; }
    public DateTime BirthDate { get; private set; }
public string Gender{ get; private set; }
    public string GetFullName()
    {
        return this.FirstName + " " + this.LastName;
    }
}
Now, if we were to create a unit test for the GetFullName method of this class it would look something like this:
public class PersonTest
{
    [Test]
    public void GetFullName()
    {
        // Arrange
        Person p = new Person("Andrew", "Stevens", new DateTime(1980, 1, 1), "male");
        // Act
        string fullname = e.GetFullName();
        // Assert
        Assert.That(fullname, Is.EqualTo("Andrew Stevens"));
    }
}
The problems:
  • Although we are only testing the GetFullName method, which only requires the FirstName and LastName to be filled, we need to pass the birth date, and gender, so we basically we are bound to the constructor.
  • If we were to change the constructor signature, we would need to change all the tests where we instantiate the Person class.

The solution:

  • Build a PersonBuilder class that takes care of creating a person in an expressive way, decoupling ourselves from calling the constructor directly.

Steps:

1. Create the PersonBuilder class:

public class PersonBuilder
{
    private string firstname = "first";
    private string lastname = "last";
    private DateTime birthdate = DateTime.Today;
    private string gender = "male";
    public Person Build()
    {
        return new Person(firstname, lastname, birthdate, gender);
    }
}
Now as you can see with the person builder we basically construct a Person based on private fields on the PersonBuilder class, but we need some helper methods to “build” our person in an expressive way.

2. Create helper methods set the private properties:

public PersonBuilder AddFirstName(string firstname)
{
    this.firstname = firstname;
 return this;
}
public PersonBuilder AddLastName(string lastname)
{
    this.lastname = lastname;
 return this;
}

Now with these methods, we can easily build our Person in a flexible and expressive way:

Person p = new PersonBuilder()
.AddFirstName("Andrew")
.AddLastName("Stevens")
.Build();
We can even improve this code and remove the Build() method by using the implicit keyword c# feature, so that we call the Build() method when we convert the PersonBuilder to a Person, ending up with the code:
Person p = new PersonBuilder()
.AddFirstName("Andrew")
.AddLastName("Stevens");
Finally, our test will look like this:
public class PersonTest
{
    [Test]
    public void TestFullName()
    {
        // Arrange
        Person p = new PersonBuilder()
.AddFirstName("Andrew")
                             .AddLastName("Stevens");
        // Act
        string fullname = p.GetFullName();
        // Assert
        Assert.That(fullname, Is.EqualTo("Andrew Stevens"));
    }
 }
And the PersonBuilder will look like this:
publicclass PersonBuilder
{
    privatestringfirstname = "first";
    privatestringlastname = "last";
    privateDateTime birthdate = DateTime.Today;
    privatestring gender= "male";
    public Person Build()
    {
        returnnew Person(firstname, lastname, birthdate, gender);
    }
    public PersonBuilder AddFirstName(stringfirstname)
    {
        this.firstname = firstname;
        returnthis;
    }
    public PersonBuilder AddLastName(stringlastname)
    {
        this.lastname = lastname;
        returnthis;
    }
    public PersonBuilder AddGender(string gender)
    {
        this.gender = gender;
        return this;
    }
    public PersonBuilder AddBirthDate(DateTime birthdate)
    {
        this.birthdate = birthdate;
        returnthis;
    }
    publicstaticimplicitoperator Person(PersonBuilder instance)
    {
        returninstance.Build();
    }
}
Conclusion:
As you can see the builder pattern has lots of advantages when it comes to testing our code. In short, the advantages are:
  • Expressiveness
    • You can build your code in an expressive way, making your tests more readable.
  • Reliability
    • Your builder acts as a wrapper around the Person class in this example, and by doing that if you need to change the signature of the Person constructor you don’t need to touch your tests, but only the builder class. As your code matures, this will make a huge difference.

Hopefully, this will help you make your tests a little more readable. If you want to add something just contact me or comment.

Leave a comment