What’s in a Name?

It’s important to choose a useful name for a test. If tests are documentation, test names are the chapter headings.

Test Names Should Not Include Should

There’s nothing wrong with the word “should.” It’s just not necessary. It’s one more word to read when trying to understand a test. “It should divide by four” and “It divides by four” express the same idea in a test name.

it "foo should return the correct answer when passing in a date" do
end

There are several issues with the above. First of all, it contains should. Second, it runs roughshod over ‘it.’ If I read the line out loud, “it foo…” does not make sense. Also, that’s a lot of words. As a developer, I want to be able to skim the tests so that I can find the test case I’m looking for.

describe "foo" do
  describe "when passing in a date" do
    it "returns the correct value" do
    end
  end
end

Isn’t that better? In addition to being more readable, it makes it painfully obvious that we’re missing another test case. Let’s add it.

describe "foo" do
  describe "when passing in a date" do
    it "returns the correct value" do
    end
  end

  describe "no date passed in" do
    it "returns the correct value" do
    end
  end
end

Be Specific

Now we have another issue: two test cases called “returns the correct value.” Come to think of it, that’s also pretty generic. Probably most test cases could be called “it returns the correct value,” “it has the intended side-effects,” or “it has the intended side effects and returns the correct value.” The question is, how would you describe the value and/or side-effect we’re looking for? Not the actual value, but its significance or meaning.

describe "foo" do
  describe "when passing in a date" do
    it "returns the count of bars before the date" do
      date = Date.today

      assert_equal 2, foo(date)
    end
  end

  describe "no date passed in" do
    it "returns the count of all bars" do
      assert_equal 4, foo
    end
  end
end

Cool. Now in this one-assertion test it doesn’t matter as much, but say we returned the bars themselves instead of the count and needed to make several assertions. Like test names, variable names in assertions improve readability.

expected_count = 2
expected_dates = ['2011-04-15', '2017-01-01']

result = foo

assert_equal expected_count, result.count
assert_equal expected_dates, result.map(&:date)

A Bit of Context

These tests are written for Minitest. If you’re using RSpec, you have an additional tool at your disposal: The context block.

describe "foo" do
  context "when passing in a date" do
    it "returns the count of bars before the date" do
    end
  end
end

Use describe when specifying the subject of the test – the class or method. Use context when talking about the circumstances under which we’re testing.

Takeaways

Let’s write some tests for our tests:

  • it “begins with a verb, not a subject” (‘it’ is the subject)
  • it “reads like a sentence” (‘it’ is the first word of the sentence)
  • it “does not contain when or if” (those belong in describe blocks)
  • it “is short” (and skimmable)
  • it “doesn’t use should as the verb”
  • it “is specific about the expected result” (what is the significance of the correct or expected result?)