Test builder pattern using fluent interface

By | November 23, 2015

This is a brief c# based tutorial on test builder pattern using fluent interface. It is one of the many ways we can tackle the problem of brittle tests. I will try to keep the example as real world as possible. As usual I will deal with the WHY before the HOW. The test builder pattern is actually based on builder pattern described in GoF book. It is sometimes quite useful in code. But it really comes into its own in the world of testing. This was first described by Joshua Bloch in his book “Effective Java”

WHY
Suppose you are unit testing a class. And somehow you wrote a constructor taking too many (read more than 3) parameters.
When you have to unit test the class, you have to create the object. And that is where the problem is.
1. You have to create a proper object, giving valid values to all the fields in it via its constructor. But suppose your test will need a proper value in only one of the fields. Still you are forced to give values to all the fields of the object. In all the tests.
2. Later when the you change/update the constructor signature, your tests fail. You have to manually and change the code creating the object in the tests.

One of reasons developers do not want to re-factor code is the fear of breaking the existing test cases. It is wrong but it happens. This highlights the importance of writing tests which are maintainable. Test builder pattern is one way of getting close to this.

HOW
Its very simple.
1. Create a builder class which creates the objects for you.
2. Provide methods in the builder which allow you to control the way the object fields are populated.

Time for code. (Fast, wasn’t it?)

As usual I will have the Interfaces. There is a bit too much of code here. Do not be scared. There are interfaces and then implementing classes. Only 3 interfaces and 9 implementing classes. For sake of completion I will be listing them all. Feel free to jump down.

The IAirConditioner.cs interface

implemented by DefaultAirConditioner.cs

and by LgAirConditioner.cs

and by CarrierAirConditioner.cs

Similarly we have IWashingMachine.cs

getting implemented by DefaultWashingMachine.cs

and by MieleWashingMachine

and by SamsungWashingMachine

There also is the IFridge.cs interface

which gets implemented by DefaultFridge

and by HaierFridge.cs

and by WhirlpoolFridge.cs


Then we have our class House.cs whose constructor takes the parameters of type washing machine, fridge and air-conditioner.

Now comes the part where you write test cases for this House.cs class.
I am using xUnit framework here.

Notice the problem here. I wanted to test the Fridge field only. But I had to provide some default garbage values to the other fields when I had to create the House object. If there are 500 such cases then you know that it is a pain.
Also notice that if I change the parameter type or count in the constructor of the House.cs class then the test has to change. Parameters have to be updated in all the places where the House.cs class object is getting created. In all those 500 tests. Sounds fun?

Let us change this.
What I will create is a small builder class for this House.cs class. Lets call it HouseBuilder.cs and here it is

It is very simple but it gets the job done.
Line 6 : This is a parameterless constructor which internally puts some default values in all the fields the constructor of the House.cs class needs.
Line 34 : This is the method which actually creates an object of type House.cs and returns the same.
Line 16 : This is where the builder does its magic of chaining the calls. It takes a parameter of the type and assigns it to the field inside it. And note the return type. It allows the method chaining which is so needed for Fluent syntax.

As a result of this our test case now has changed!!!

Immediately one benefit will jump out. The parameter which is crucial to my testing is the one getting passed explicitly. The builder is taking care of passing the default values to the fields which my test is not really concerned with. If this constructor had 12 parameters (Don’t do it) then this is a big big win.

Another thing which might have skipped your attention is the readability.

is more readable than

Yet another benefit is this. Suppose for some weird reasons you just need a object of House class. But you are not going to do anything with it. Just one particular silly function needs a House class object. In that case all you need to do is to create an object with default values. With test builder pattern this is particularly easy.

But the greatest benefit is this. Suppose you being the evil you are, added one more parameter to the constructor of the House.cs class. And your test cases change.

All 500 of them. Yikees !!!!

But the story is different with the builder.
You just add the new field to the builder HouseBuilder.cs like this

And the test case? Does it get changed? NO

Of course you will be writing new unit tests for the newly introduced parameter. But the key point is that the existing tests were still working. Nothing broken.

And you as a developer now have one reason less not to refactor your code to make it better.

Leave a Reply