skip to main content

Blog | About me

Don’t “check” or “verify” in your tests

Clearly communicating intent is an underrated skill in writing tests. In automated tests especially it is tempting to think that since the code defines what gets checked, the human-readable parts of the test — the description or the method names — aren’t as important to get right.

I often see people define custom assertion functions to avoid duplicate code (a good thing!) but then end up giving them names like this:

verifySystemState() { ... }
checkReturnCode() { ... }

The problem with this is that instead of describing what the system does, they’re describing what the test does. The test is going to verify the system state or check the return code. In most code this makes sense: functions should say what they do, and usually how they do it shouldn’t matter to the caller. With functions used in tests, that’s only partially true. I still might not need to know how the thing is verified or checked—I can always go to the function definition for that—but as a reader care a lot more about why I’m calling that function than what the function does. The name should reflect that.

I see the same mistake made on test names and descriptions themselves. Constructions like this:

it("checks the response code", () => { ... });

is (incorrectly!) describing what the test does: The test checks the response code. Almost every JavaScript test framework I’ve used allows using either test or it as the function name defining a test. Take advantage of what it here means: it’s not an abbreviation or shorthand for something technical, it’s meant to be read as the first word in that specification describing the system. Constructions like:

describe("Foobar", () => {
    it("should be a woozle", () => { ... });
    it("should return an array", () => { ... });
    it("throws an error when called with a boolean", () => { ... });

are a series of sentences describing a Foobar, not describing the test:

  • It should be a woozle.
  • It should return an array.
  • It throws an error when called with a boolean.

Less charitably, this can also be a side effect of the writer not really understanding the system being tested. Take test names like these:

it("checks the return code", () => { ... });
it("handles arrays", () => { ... });
it("returns", () => { ... });

Writing “it checks the return code” might be an answer to thinking “I should probably check what the return code is” rather than thinking “This should return a 200 OK so let’s write a test for that.” All of those examples suggest the writer had an idea of what to do next but little idea why or what to expect when they did it. Even if they did, a reader trying to understand these tests in 6 months surely won’t.

Instead of being written as commands telling the test automation what to do next, these test names and methods should answer a question or be a statement of fact.

  • Question: “What should the return code be?”
  • Answer: “It should be a 200 OK.”

It’s useful to module them after normal assertions or expectations:


Wrapping the details of how we get the necessary information in helper functions, we’d use function names like:


(I’m still being a bit messy here using very generic sounding names; I get equally annoyed at variable names like “result” and “value” in real test code.) The point is the structure: “X is Y“, not “Do Z“.

While you can still create better names using “verify”:


it’s too easy to drop the “is Y” part when “Verify X” is still a complete sentence. Slightly better, while “Check X” is a complete sentence, “Check that X” is not.

A strict rule for it would be silly, but if helps, put “check” and “verify” on your list of weasel words to avoid in test automation. While not themselves as bad gems like “correct” and “valid”, they’re enablers of ambiguity.

About this article

Leave a Reply