mariuszwojcik

Becoming a better developer by blogging

Create test objects using Builder pattern and methods chaining

2 Comments

In my previous post “Create test objects using Factory Methods or Object Mother pattern” I described how Factory Method and Object Mother patterns can be used to help with creating object instances. Presented solution allows to remove code duplication from unit tests making them easier to adopt changes in tested objects, but doesn’t help much with test code readability, which is very important factor in maintaining unit tests. Using sample Address class from the previous article, imagine following code:

            Address address = new Address("Poland", "Slask", "Zabrze", "Chrobry", "13", "46-230");

For someone who doesn’t know a lot about Poland’s geography and addressing system, it is really hard to recognise which parameter represents County, City or Street, and when it comes to numbers the situation is even worse. To solve the mystery meaning of parameters, reader must go to class definition or use help from tools such as IntelliSense. Maybe it doesn’t seem like much effort, but it breaks the reading process and de-concentrates reader. It is like reading a book in foreign language with many new words. The reader spends more time going through the dictionary than reading a book and in effect doesn’t remember much from what she read. Soon, the reader stops checking every unknown word in the dictionary and starts to assume its meaning from the context, although in many cases the assumption is wrong (Some of the novels I read when I was learning English I read several times, and every time it was like reading different book). To help the reader with understanding the unit test, it must be written in a way that there is no need to leave the page or assume any meaning, but code is kept conscience and free from duplication.

Now, look at following example:

            Address address = new AddressBuilder()
                .WithCountry("Poland")
                .WithCounty("Slask")
                .WithCity("Zabrze")
                .WithStreet("Chrobry")
                .WithHouseName("13")
                .WithPostCode("46-230")
              .Build();

This time, to create an instance of Address we used AddressBuilder which is an implementation of Builder pattern. We also used Method chaining technique which simplifies the code required to build an object. The above code is much easier to read and doesn’t require from reader the intensive knowledge of Address object, making reading unit tests written by or colleagues a real pleasure.

Below is the AddressBuilder class:

    internal sealed class AddressBuilder
    {
        #region private members

        private string _country;
        private string _county;
        private string _city;
        private string _street;
        private string _houseName;
        private string _postCode;

        #endregion

        public Address Build()
        {
            return new Address(this._country, this._county, this._city, this._street, this._houseName, this._postCode);
        }

        public AddressBuilder WithCountry(string country)
        {
            this._country = country;
            return this;
        }

        public AddressBuilder WithCounty(string county)
        {
            this._county = county;
            return this;
        }

        public AddressBuilder WithCity(string city)
        {
            this._city = city;
            return this;
        }

        public AddressBuilder WithStreet(string street)
        {
            this._street = street;
            return this;
        }

        public AddressBuilder WithHouseName(string houseName)
        {
            this._houseName = houseName;
            return this;
        }

        public AddressBuilder WithPostCode(string postCode)
        {
            this._postCode = postCode;
            return this;
        }

        public AddressBuilder InGuildfordUK()
        {
            this._country = "United Kingdom";
            this._county = "Surrey";
            this._city = "Guildford";
            this._street = "St. George Av.";
            this._houseName = "Elliot House";
            this._postCode = "GU3 1DA";
            return this;
        }

        public AddressBuilder InBrentfordUK()
        {
            this._country = "United Kingdom";
            this._county = "Middlesex";
            this._city = "Brentford";
            this._street = "Windmill Road";
            this._houseName = "5";
            this._postCode = "TW8 9NA";
            return this;
        }
    }

The two methods at the end: InGuildfordUK and InBrentfordUK make building sample addresses easier and can be used in tests, where the exact content is not as important as the fact that the addresses are different. The example can be a test of collection with addresses which doesn’t allow duplicated entries:

            // addresses is a collection which doesn't allow duplicated entries

            addresses.Add(new AddressBuilder().InBrentfordUK().Build());
            addresses.Add(new AddressBuilder().InGuildfordUK().Build());

By using descriptive names we are telling a reader that the former address is in Guildford in the United Kingdom, while the latter address is in Brentford, UK.

References:

About these ads

Author: Mariusz Wojcik

I am senior software developer working with .NET C# and, recently, Microsoft Azure.

2 thoughts on “Create test objects using Builder pattern and methods chaining

  1. Great pattern. I need to try it in my tests cluttered with spaghetti like generated test data ;]

  2. Great example. Simple, concise, and right to the point. Makes it easy to understand how this pattern can make your tests a lot more readable. Thank you.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.