There’s a fair amount of ideas out there about what you should name your unit test methods. Until recently, I had followed a variation of BDD‘s naming scheme, “shouldDoSomethingWhenGivenSomething”. BDD-esque naming is still what I consider the best naming scheme that I’ve seen out there (what I’m going to show you in this post doesn’t count for some interesting reasons that may or may not be clear to you when you’re done reading it). It’s certainly not bad, but I’ve got a few bones to pick with it, and, eventually, a solution.
Problem #1: Difficult Searching/Distinguishing
First off, BDD’s naming convention lends itself to long names that have repeated parts between different tests. For example, “shouldThrowMyExceptionWhenGivenInvalidParameter1” and “shouldThrowMyExceptionWhenGivenInvalidParameter2”. This can be a pain to deal with when a test suddenly goes red and you have to find it among all your other test methods by name in order to see what might be the problem.
In Clean Code by “Uncle Bob” Martin, Martin writes about long, similar names. As much as possible, you want to put the parts of the name that are different at the beginning of the name. This makes it much easier to distinguish which one you’re looking at quicker, which speeds up search time, if needed. Technically, his advice was meant for class names, but it still applies anyway, for the same reasons.
Problem #2: Shorthand
Another thing detrimental to this naming convention is the fact that you automatically try to do a little bit of shorthand. People don’t like their method names to be a mile long, and for good reason (though, not such a good reason when it comes to tests, since they’re called via reflection), but it often leads to people leaving out little words that they don’t feel are important to the meaning. Usually, they aren’t that important, but sometimes removing those words makes the meaning ambiguous or misleading. Considering the fact that your tests and their names are supposed to be living documentation, you don’t want to confuse people.
Problem #3: Restricted Names
The last problem overlaps with previous problem; method names have restrictions. In most languages, you can start the name with an underscore or letter (possibly some other random character) and the rest of the characters can be any alphanumeric character or an underscore. This doesn’t allow any special punctuation characters such as apostrophes. This limitation can cause one of two different things: possible misunderstanding of meaning (just like with the last problem), or an overly lengthy name that works around the missing character.
My solution to all of this is to give up on really useful names. Remember, though, that I said that BDD’s naming scheme was good, and I still intend to sort of use it. But I’m still saying that you should stop worrying so much about the names of your test methods. I’ll give a few suggestions in a little bit, but first I’ll explain why the names of the tests aren’t that important.
The reason that the name doesn’t matter is because we’re not putting all that useful information into the name anymore. We’re moving it to comments.
Why comments? Because they offer freedom. You can format them or use punctuation in them. You can put even more information into them without making it impossible to read.
Documentation comments, such as javadoc, are even better! They not only explain everything in the source code, but also in the documentation. This means that people don’t necessarily need to dig through the source to learn from your tests.
A good, well-defined, and consistent format for this documentation is important. From my limit experience at this point, I would try something similar to the following:
/** * Quick summary, similar to what you would have named the method in BDD, mentioning the name of the method being tested * Method: methodName(ParamType1, ParamType2, etc) * @param param1 - describe the essential information about the first parameter * @param param2 - describe " " " " the second parameter * ... * @return the expected output (or other behavior), given the parameters sent in */
You don’t have to use the built-in tags if you don’t want to. You could use Precondition and Postcondition sections (or something similar) instead.
Back To Naming The Methods
When it comes to naming the test methods, there are still 2 things you should strive for. The name should be easily searchable, and the name should probably include the name of the method being tested.
Numbers, when put in order, make searching relatively easy. You don’t even need to put the number at the front for improved searchability, since the number will stick out like a sore thumb. Plus, they will all likely line up, making it easier to scan for the number. My suggested naming convention here is “methodNameTest1”, “methodNameTest2”, etc. You can use anything you want, though. You can even skip the method name (not recommended) and go with “test1”, “test2”, etc.
Of course, just like everything else, this has a downside: it requires discipline. First, it requires the discipline to type up the full comment documentation to begin with. Second, it requires the discipline to keep the comment up to date. Luckily, the second discipline will generally be less of a problem compared to comments in general. This is because, even if you change the implementation of a test, you very rarely change the meaning. Also, if the test’s idea becomes outdated, it’s usually deleted, not changed.
So, that’s my idea. Do you have anything to say on the subject? Comment below and let me know. Also, don’t forget to Like and Share if you agree with what’s above. If this is as good of an idea as I think it is, we should probably try to get this out there as far as possible.
I just want to make it clear that this is just an idea at this point. I’m very open to criticism fir this.
I recently found out about a JUnit Runner that allows for nesting that helps with the naming problems. Check out Petri Kainuainen’s article about it to see why it’s so great.