TL;DR: test quality is not just about verifying correctly whether your code works, it’s also about making your test easy to read and understand. You can do that by structuring your test using the four-phases xUnit standard.

People don’t write tests to be read, they write them to be executed

One of the main reasons to write tests is to have an automated way to check if your code is doing what you expect it to do. That means, trying to verify its correctness. Your test suite acts as a safety net that guarantees your software will continue to work as expected while you refactor, build new features or fix bugs. That’s amazing! But, throughout the years, software developers discovered that tests can be even more than a safety net.

Write tests as examples of how to use your code

A test is an example of how to use your code, not just a way to verify its correctness. Seeing tests as examples of how to use your code changes a little bit the priorities you have when writing them. If the test should serve as an example, then it should be easy to read and understand. Therefore, you should also focus on test readability, not just test “executability” (I know, weird word). One way to improve readability of a piece of text (or code) is to write it in a way the readers are used to, a structure that they expect, some standard way… Let’s think about that.

Back at your school days, you learned that when writing an essay, you’re supposed to structure it in: introduction, body and conclusion. Why? Because that structure helps you to better express your ideas. That means, it helps the reader to understand your message. Is there any equivalent of that for automated tests writing? In fact, there is. It’s called the xUnit structure.

Structure your tests using the xUnit standard

First, let’s see a test that can have its readability improved:

describe Stack do describe "#push" do it "puts an element at the top of the stack" do stack = Stack.new stack.push(1) stack.push(2) expect(stack.top).to eq(2) end end end

One can understand the test above, but still, it’s not easy to quickly scan the test and see that it has logical parts. Those parts would be the the xUnit phases.

The standard xUnit test structure is composed of 4 phases: setup, exercise, verify and teardown.

Setup: this where you put the object under test in the necessary state for the behavior you want to check;

this where you put the object under test in the necessary state for the behavior you want to check; Exercise: when you send a message to your object;

when you send a message to your object; Verify: here, you should check if the object under test behaved the way you expected;

here, you should check if the object under test behaved the way you expected; Teardown: basically where you clean up stuff in order to get your system back to the initial state.

Now, let’s re-organize the test above making explicit that there are different logical parts:

describe Stack do describe "#push" do it "puts an element at the top of the stack" do # setup stack = Stack.new # exercise stack.push(1) stack.push(2) # verify expect(stack.top).to eq(2) end end end

It’s easier to scan, isn’t it?

About the comments, no, we don’t need them. I added them in order to make the example clear. Let’s remove them and keep this structure:

describe Stack do describe "#push" do it "puts an element at the top of the stack" do stack = Stack.new stack.push(1) stack.push(2) expect(stack.top).to eq(2) end end end

One can say that we just added two line breaks, that’s true. But that’s just the how, not the what. The what is: improving test readability. The how is: structuring the code based on the xUnit four-phase standard, by adding two line breaks. Got it?

Using a standard structure to ease the communication of an idea is not something new. As an example, Rails does that when it generates a standard directory structure. When entering on a new Rails project and scanning it, you know your way and where stuff are because you already expect a defined structure and you are used to it. It’s not something completely new, you’re used to that structure. I could also say that even Ruby uses that concept when it talks about the “principle of least surprise”, but maybe I would be going too far. So, let’s get that wrapped up.

Why care about test readability?

So, why should I care about all of that stuff? I mean, isn’t just having my test suite on green enough? No.

Test readability will be really important in a lot of situations. Like when a test gets red, someone needs to fix it. In order to do that, one needs to understand what the test is about. If the test is well structured and easy to read, they can fix it faster.

Also, if you think about your tests as examples of how to use your code, someone that is trying to use a class that you wrote, can see how it’s done in the tests. The test readability will be equally important here too.

So, what about you, how do you improve your test’s quality? How do you improve your test’s readability?