Why Building Units for Test Using Fluent Syntax is Worth the Time? – Mike Wardle

Why Building Units for Test Using Fluent Syntax is Worth the Time? – Mike Wardle

Recently I found myself working on a system that was written entirely in a TDD manner. Code coverage was amazing, but I needed to make changes. I was adding some classes and went about it with all the right intentions, all TDD. So I started to write tests for my first class. Set up the system under test (my as yet unwritten new class) with all its dependencies injected through the constructor as mocked out interfaces.

All was well, I continued to flesh out the requirements of the class as unit tests. They all failed. Then I added code and made all the tests pass with the mocked dependencies. At this stage I had a fully functioning class that did everything I needed it to do and the code was beautifully covered by a host of unit tests.

1
Then came phase 2 of the project and with it the need for the class to do something more. While the open-closed principle would suggest we don’t change the class, but maybe derive from it, add the new functionality to the derived type and only add the new dependencies to this derived type. I didn’t do this. Rushing in headlong, I decided to crack open the stable, functional, fully tested and robust class.

This meant writing a number of new unit tests to prove the new functionality. The class needed to interact with a further dependency, and this meant extending the constructor to take an extra parameter.
pexels-photo-160107

Again I could have extended by adding a new constructor, leaving the old one but again that’s not what I did. I changed the constructor and instantly broke every existing unit test. Actually, I didn’t stop them passing, I stopped them compiling. This meant going through and adding the new dependency to every unit test. Very time-consuming.

At this point, I was reminded of a pattern I had used in the past. The one I should have used from the outset, but it would have taken an extra ten minutes at the start of development, which I chose not to do. So now I was left with something that would take over an hour to fix but saved me ten minutes a couple of weeks ago! Technical debt if I’ve ever seen it.

So to the pattern, fluent builders. The idea is rather than creating the class you want to test, you create on an object that will build it for you, the builder. Then you tell the builder what dependencies you want to inject into your system under test and ask it to build it. The fluent aspect comes from the way you do this. Imagine how you would phrase it. “I want a cup of coffee, with milk and with two sugars.  Or in code

2
Backed by a class

public class CupOfCoffeeBuilder
{
public bool Milk{ get; set;}
public int Sugars{ get; set;}
CupOfCoffeeBuilder ()
{
// initialise any default values here
}

public CupOfCoffeeBuilder WithMilk(bool choice)
{
_milk = choice;
return this;
}

public CupOfCoffeeBuilder WithSugars(int howMany)
{
_sugars = howMany;
return this;
}

public CupOfCoffee Make ()
{
return new CupOfCoffee(_milk, _sugars);
}
}

This all means that when creating the cup of coffee, I only made it when we know all of the optional parts that go into it, the sugar and milk. In other words, we could make a cup of coffee with any combination of milk and sugar but we only have one make method, and that means only one call to the cup of coffee constructor.

This means for my case if I had used a fluent builder, adding the extra dependency would have meant adding one property, one method and one parameter to the single constructor call within my builder.

5

6

The other advantage of this approach is that your tests become instantly more readable. And who can argue with code that is easier to read and easier to maintain?

Thanks to Mike Wardle for being our guest writer this week.

If you would like to read our blog next week feel free to subscribe below!

© Ronald James Ltd. 09824756. Q16 Business Exchange, Quorum Business Park, Newcastle upon Tyne, Tyne and Wear, NE12 8BX, United Kingdom. Website by Outlines Design.