TotT: Naming Unit Tests Responsibly
For a class, try having a corresponding set of test methods, where each one describes a responsibility of the object, with the first word implicitly the name of the class under test. For example, in Java:
class HtmlLinkRewriterTest ... {
void testAppendsAdditionalParameterToUrlsInHrefAttributes(){?}
void testDoesNotRewriteImageOrJavascriptLinks(){?}
void testThrowsExceptionIfHrefContainsSessionId(){?}
void testEncodesParameterValue(){?}
}
This can be read as:
HtmlLinkRewriter appends additional param to URLs in href attrs.
HtmlLinkRewriter does not rewrite image or JavaScript links.
HtmlLinkRewriter throws exception if href contains session ID.
HtmlLinkRewriter encodes parameter value.
Benefits
The tests emphasizes the object's responsibilities (or features) rather than public methods and inputs/output. This makes it easier for future engineers who want to know what it does without having to delve into the code.
These naming conventions can help point out smells. For example, when it's hard to construct a sentence where the first word is the class under test, it suggests the test may be in the wrong place. And classes that are hard to describe in general often need to be broken down into smaller classes with clearer responsibilities.
Additionally, tools can be used to help understand code quicker:

(This example shows a class in IntelliJ with the TestDox plugin giving an overview of the test.)
Remember to download this episode of Testing on the Toilet, print it, and flyer your office.
I wish I could print and put this on our toilet, but I work on a bank ;-(
ReplyDeleteOn the subject of names, changing the case of abbreviations doesn't help readability much. How about HTMLLinkRewriterTest rather than HtmlLinkRewriterTest? CamelCase is just a guide.
ReplyDeleteI love self-documenting code. :)
ReplyDeleteNot really on topic, but this example reminds you that it's always good style to use words like "has" or "is" or "does" when dealing with anything remotely boolean. Though I always try to avoid negations like "not" (e.g. "DoesNotRewrite") and rather use positive names (dunno, "void test(!doesRewriteImage...)" or "testDoesUseStableImageLinks" or whatever). But of course I'm just saying this in general, not applicable to this snippet.
So where are the real blog posts on testing, data driven practices, extensiblity, deployemnt automation..? I really hope this isn't the best stuff Google has for testing advice.
ReplyDeleteThe TestDox functionality of PHPUnit makes this "agile documentation through test names" accessible, as does its role model, the TestDox extension for JUnit.
ReplyDeleteI'd like to know more how a class in IntelliJ with the TestDox plugin gives an overview of the test.
ReplyDeletePerhaps you guys can elaborate more. I am not feeling very motivated.
Linux 2.6.20 got released yesterday. One of the "noteworthy" news is fault injection.
ReplyDeleteAny of you guys ever used this for testing purposes? I think it could be a great aproach!
Something seems wrong here to me. Assertions about what a class or function should do or not do should be, well, assertions. Tests are attempts to make a class violate its contract; assertions (or postconditions, if you prefer) check that the contract is not being violated.
ReplyDeleteNaming test cases after aspects of the class contract implies a one-to-one relationship between test cases and postconditions. This is arbitrary and often wrong. Every test case should pass every assertion without triggering it, and there may be many more parts of the input space that need special testing than there are postconditions.
Exactly what a class should do with its assertions in production is an engineering decision, but they belong in the source code and should be checked for _every_ test case. Tests should be generated and named according to an understanding of the input space, not the class contract.
Weekly turned montly? Where's the next installment? Awaiting...
ReplyDeletesimilar to testdox, there is also a spec plugin for nose (a python test runner) that just came out.
ReplyDelete