I think a lot of developers look at writing unit tests the way Saint Augustine thought of chastity: Oh Lord, give me the strength to write unit tests, just not yet. We know we should write unit tests, but somehow we keep putting it off. Well here are five things to keep in mind while you are trying to work up the ambition to write that test:
1) Don’t take all day
Unit tests that take an hour to run will be run at most once per hour. Who am I kidding? Unit tests that take an hour to run will get run once or twice a week if you are lucky. If you want developers to run your unit tests, they gotta go quick. They gotta be automated. And they gotta avoid a two hour or even a two minute set up.
Don’t get me wrong – longer running tests are fine, in fact they are great. Longer running tests that pound away at the database, that require all the servers to be running, that stress the heck out of the system are great. They are just not unit tests. Unit tests should run quick with the setup that every developer has. They are your first line of defense, and in order to be any good they must be run often.
2) Silence, please
OK, this may be just me, but I hate chatty unit tests. When I run a test I want a simple answer to a simple question: work or no work? I don’t want to know how many elements are in the list, that you are now entering this or that method, and I certainly don’t need help with today’s date.
If the test fails, then I will crank up the old debugger or put in my own logging statements. A simple yes or no people.
3) Skip catching exceptions
Question: What is the difference between this JUnit test:
Public void testWidget() throws WidgetException {
Widget w = new Widget();
w. doSomething();
}
… and this one?
Public void testWidget() {
try {
Widget w = new Widget();
w. doSomething();
}
catch( WidgetException
we) {
fail(“widget failed”, we );
}
}
The difference is that, should a WidgetExcpetion get thrown, the the first code fragment will fail with a nice stack trace pointing at the location of the actual failure. The second bit of code will also throw an exception saying that the test failed. But it will print a stack trace pointing the reader back to, well, the fail() statement. Buried somewhere in the nested stack traces will be the information you need to really figure out what went wrong. In short, the first example is not only less code, it works better!
If you do a lot of exception catching like this in your unit tests, you are working hard to ensure that everyone’s attention is called to the wrong place. Magicians have a term for this: misdirection. Magicians like misdirection, but then they are actually trying to obscure what is going on. Presumably you have other goals in mind.
Remember, unless you are testing some complex exception handling, if the test throws an exception, your work is done. Save the enthusiastic error handling for the times when it will make your program better.
4) Don’t write the War And Peace of test methods
Why is it that when some engineers start writing unit tests, they are suddenly transported back to Prom night? Ordinarily mild mannered programmers, who would never think of writing a 60 line method in real life, suddenly go on a drunken binge, spewing out 1700 line test methods, sans comments, sans structure, sans thought. Yes the rules are different when you are writing tests. No you don’t have to follow all the conventions, and no you don’t have to be as careful.