Bad Tests Good Tests - True, False and Magic Switches

This post is a part of my new free book about tests. You can learn more here. Please share your comments (so the book is better).
The idea for the book is to discuss examples of test classes and to present ways of making them better.

Click here for other posts about tests.

If we expect our tests to act as a documentation then we need to put some effort into their readability. Consider the following example:

server = new MockServer(responseMap, true,
                new URL(SERVER_ROOT).getPort(), false);

This single line of code is responsible for creation of the server object of the MockServer class. It is later used in test code.

Nice, but what the heck does true and false mean here? What kind of server is actually created?

I do not expect you to have JavaDocs for MockServer (which sounds like a utility class create especially for testing purposes), which means you need to browse the source code to find out. This is not a major problem (but it may be - depending on the complexity of MockServer class), however this is a nuisance. And it means that this test does not play the role of documentation very well. In order to understand the test case we need to browse another documents (i.e. source code). This is not a tragedy but this is not good either.

And what can we do about this? There are at least two options.

First, we could create some static variables with intention-revealing names, like this:

private static final boolean RESPONSE_IS_A_FILE = true;
private static final boolean NO_SSL = false;

server = new MockServer(responseMap, RESPONSE_IS_A_FILE,
                new URL(SERVER_ROOT).getPort(), NO_SSL);

Now there is no doubt what kind of server is created. It does not use SSL and responds with a file. Better, isn’t it? And we haven’t had to work very hard to achieve this effect.

Second approach requires some more work. Yeah, you guessed it already - we could use a test data builders idea and express very clearly what kind of server is required. For example like this:

server = new MockServerBuilder()
                .withResponse(responseMap)
                .withResponseType(FILE)
                .withUrl(SERVER_ROOT)
                .withoutSsl()
                .create();

Is this approach better than the previous one? Not necessarily, as it definitely requires more work. However the fact that we control the API allows us to shape it according to our liking. Maybe in the domain that this MockServer works, this is a perfect solution (this one implicitly sets the "no-SSL" option, and shortens type and URL setting):

server = new MockServerBuilder()
                .createFileServer(SERVER_ROOT)
                .withResponse(responseMap)
                .create();

Probably the more complex and more frequently created the class in question is, the more we benefit from test data builders.

Please comment using