Should We Use Should In Unit Tests?

It’s a good question. To give the consultant’s answer - it depends - but in most cases, I do not think it is particularly helpful.

No doubt you would have seen and perhaps written a test beginning with ‘should’:

it('should show placeholder text when user has not entered text', ...);

The use of should is a gripe for me, because every time I see it, my mind thinks “well, when should it not do that!”. Nearly every time I question this during a review, eyebrows are raised. Am I being pedantic, petty, or just making sure that I have full a understanding of what I’m being asked to review? In most cases, the ambiguity was completely in my head. The code under test is always required to produce the behaviour that’s being tested, under those conditions. But the use of ‘should’ made me doubt it.

This word, or the adjective “RECOMMENDED”, mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.

The same document additionally defines MUST, so perhaps that is a suitable replacement?

This word, or the terms “REQUIRED” or “SHALL”, mean that the definition is an absolute requirement of the specification.

Well, it could work, as could SHALL. But can we do better?
What’s the impact if we remove should altogether?

The first thing that happens is we need to change from a passive, to an active tone of voice:

it('shows placeholder text when user has not entered text', ...);

Not only have we saved characters, we’ve removed the ambiguity behind the test case. If the test fails, we know exactly why it’s failing - the placeholder text failed to be rendered.

The convention of the ‘should’ prefix seems to originate with behaviour-driven-development, a notion I am a big fan of. In the past I’ve blogged about structuring tests, such that they align with the behaviour of what’s being tested. Tests communicate and demonstrate the intent of the code. Aim for tests to be unambiguous.

Too often I’ve seen hand-wringy, passive tests that are tightly-coupled to the particular implementation that they’re meant to be testing. It’s important to avoid that, else your tests end up testing that the code does what the code does, not what it is actually doing. You can break this trap by dropping ‘should’ from your test names. It forces you to write tests from the user’s perspective. That’s what truly matters here.