Seven Steps to Great Unit Test Names





You can find many good blog posts on what to name your tests. We present instead an appropriate strategy for when and how to think about test naming.
  1. Don't sweat the initial name. A bit of thought about what you're testing is essential, but don't expend much time on the name yet. Type in a name, quickly. Use AAA or Given-When-Then to help derive one. It might be terrible--we've named tests "DoesSomething" before we knew exactly what they needed to accomplish. We've also written extensively long test names to capture a spewn-out train of thought. No worries--you'll revisit the name soon enough.
  2. Write the test. As you design the test, you'll figure out precisely what the test needs to do. You pretty much have to, otherwise you aren't getting past this step! :-) When the test fails, look at the combination of the fixture name, test method name, and assertion message. These three should (eventually) uniquely and clearly describe the intent of the test. Make any obvious corrections, like removing redundancy or improving the assertion message. Don't agonize about the name yet; it's still early in the process.
  3. Get it to pass. Focus on simply getting the test to pass. This is not the time to worry about the test name. If you have to wait any significant time for your test run, start thinking about a more appropriate name for the test (see step 4).
  4. Rename based on content. Once a test works, you must revisit its name. Re-read the test. Now that you know what it does, you should find it much easier to come up with a concise name. If you had an overly verbose test name, you should be able to eliminate some noise words by using more abstract or simpler terms. You may need to look at other tests or talk to someone to make sure you're using appropriate terms from the domain language.
  5. Rename based on a holistic fixture view. In Eclipse, for example, you can do a ctrl-O to bring up an outline view showing the names for all related tests. However you review all the test names, make sure your new test's name is consistent with the others. The test is a member of a collection, so consider the collection as a system of names.
  6. Rename and reorganize other tests as appropriate. Often you'll question the names of the other tests. Take a few moments to improve them, with particular focus given to the impact of the new test's name. You might also recognize the need to split the current fixture into multiple fixtures.
  7. Reconsider the name with each revisit. Unit tests can act as great living documentation -- but only if intentionally written as such. Try to use the tests as your first and best understanding of how a class behaves. The first thing you should do when challenged with a code change is read the related tests. The second thing you should do is rename any unclear test names.
The test names you choose may seem wonderful and clear to you, but you know what you intended when you wrote them. They might not be nearly as meaningful to someone who wasn't involved with the initial test-writing effort. Make sure you have some form of review to vet the test names. An uninvolved developer should be able to understand the test as a stand-alone artifact - not having to consult with the test's author (you). If pair programming, it's still wise to get a third set of eyes on the test names before integrating.

Unit tests require a significant investment of effort, but renaming a test is cheap and safe. Don’t resist incrementally driving toward the best name possible. Continuous renaming of tests is an easy way of helping ensure that your investment will return appropriate value.

9 comments:

  1. Great article!

    One thing I would add to this is "Don't be worried about length when naming your tests...just be clear!"

    Having done a lot of mentoring on TDD I have come across an aversion to long method names and although I agree with this, somewhat, in non-test methods I urge people to be as descriptive as possible when naming tests. At a glance someone should be able to read the signature of a test method and know exactly what is being tested and more importantly know exactly why the test would fail.

    ReplyDelete
  2. Some examples would be helpful to illustrate the point. All of these are for the same test case.

    test0() <-- no lie, i actually saw this as a test name

    badInsert() <-- better, but still not capturing intent

    coverErrorPath() <-- ick, not much better than test0

    ensureUniquenessByRejectingInsertionOfDuplicate() <-- aaaahhhh

    ReplyDelete
  3. You need an example.

    it "should create a graph containing the current Post's title" do
    post = posts(:Jammin)
    map = MindMap.new(post)
    dot = map.to_dot
    dot.should match(/graph mind_map \{/)
    dot.should match(/post_#{post.id}.*label = .#{post.title}/)
    end

    http://broadcast.oreilly.com/2009/02/merb-mind-maps.html

    Now note that test names (and, uh, "spec" names) don't need Programmer-Speak. They can be complete sentences, because they should rarely be called directly. And modern test runners can use real strings, not function names, as test names.

    ReplyDelete
  4. @Anonymous:

    The test name is 1/3rd of the picture. The fixture name, the test name, and the assert together are descriptive. "Expected exception not thrown in MapInsertions.rejectsDuplicate()" means that "rejectsDuplicate" is a fine name.

    Also realize that the context includes the other tests. If you look at the list of tests, then any one test becomes _more_ meaningful.

    This way we can have the virtues of uniqueness and terseness in our naming... eventually. In the mean time, a big long test name is just fine.

    ReplyDelete
  5. At least one tweeter thought this card represented "horrible" advice. I know it's hard for people to get past an initial (purposefully) contentious statement.

    Revisiting your test names is actually very important advice that works very well in practice.

    What truly matters is end product. Not the thought process involved in its creation, and not the order in which things were created. The test name itself, and the meaning it bestows on the next developer that must understand the test, is extremely important. And I do mean extremely.

    Yes: Most of the time you should know what you are test-driving. You might even want to consider working backward from an end goal ("write assertions first"), because it can help you write the test as more a declaration of intent, instead of a progression of step implementations. That's a suggestion. Try it. If it helps you, that's great, and if not, don't feel other dogmatic folks make you feel bad about not working that way.

    Anyone who's coded extensively has found times when they needed to explore. "I know roughly what I need to do, and I think I know how to accomplish that, but I'm not sure precisely how to express it." Or: "I know the steps I need to take to accomplish my goal, but I'm not sure how to express those in a more abstract sense." Either way, you could sit and debate names for five minutes, ten minutes, or maybe more, before you coded anything. Or you could sketch out what you think needs to happen, get it to work, and revisit what you really thought you were doing.

    Never be blocked! TDD can allow you to probe at an appopriate direction for the system, them refine the definition of that notion once it appears to be what you're looking for.

    A test name need not be perfect before you begin coding. In fact, I find any such "rule" against the spirit of agile and more in the realm of analysis paralysis. We accept that up-front design can never be perfect or complete, so why would we insist on the same fallacy for test names?

    Better: Accept that you can come up with a pretty darn good name in quick order. Realize there will be important learning as you implement the test. Finally, admit your original test name might not have been perfect, and fix it.

    Our problem is not the thinking process people use to arrive at a solution. It is that they are unwilling to shed their hubris (or laziness, or whatever) and admit that there might be an even better one.

    ReplyDelete
  6. In some particular situations, clients or some specialists in their company want to get access to your unit test. In one of my project, I had to produce human-readable documents from unit and integration tests. Good test names was essential.

    ReplyDelete
    Replies
    1. Yes they are essential! I view good naming as one of the most important things you can focus on. Like with everything else "agile," you visit it initially, invest a bit of time, revisit it when you think you're ready to move on (commit/push your code), and reconsider it yet again down the road when you see it again.

      Delete
  7. Replies
    1. You know, here on the blog (and our personal blogs, and the IL blog) we're giving ideas away for free. I hope there are a lot of people using the ideas they get here, and I don't mind overly much if they don't remember where they got them.

      A little fame for an author is a nice thing. But we didn't invent everything we know either, and lord knows if we will ever remember where we got it all. We try to be good about it, but heck we see stuff copied.

      We see a lot of people "pirating" the book, too. It's something that happens, and certainly full-blown copyright infringement is more upsetting and actionable, but if any particular idea finds its way from the blog or book into the world where it helps someone then we're pretty darned happy.

      Delete

Note: Only a member of this blog may post a comment.