How do you verify your component throws an exception?
Most tests verify something works. But exceptional cases are important too, and what do many exceptional cases do? Throw exceptions of course.
So how do you verify your component throws an exception?
Real possibilities
My favourite idiom for testing exceptions is:
try {
map.locateCoordinates("Alpha Centauri");
fail();
} catch(OutOfBoundsException ex) {}
The code will fail() if the errant statement falls through to it; i.e. if the errant statement does not throw an exception.
Another idiom is:
boolean exceptionThrown=false;
try {
map.locateCoordinates("Alpha Centauri");
} catch(OutOfBoundsException ex) {
exceptionThrown=true;
}
assertTrue(exceptionThrown);
I prefer the former as it’s more terse. Some may say it’s less intuitive, but that’s the whole point of idioms; they’re a good thing because they compress code, and as long as you can internalise their meaning, you can recognise what’s going on in a blink. In any event, they’re variations on a theme.
A different approach is to encapsulate the exception-throwing code in a command interface:
verifyExceptionThrown(new ExceptionThrowingCommand() {
public void exceptionThrowingBlock() {
map.locateCoordinates("Alpha Centauri");
}
}
...
private void verifyExceptionThrown(ExceptionThrowningCommand command) {
try {
command.exceptionThrowingBlock();
fail();
} catch(OutOfBoundsException ex) {}
}
In this case, we’ve extracted out the idiom for verifying an exception is thrown. Unfortunately, it didn’t do much good, because calling it - due to the anonymous class declaration - is actually about as lengthy as doing the whole thing anyway! This approach does have the benefit of isolating the standard approach to exceptions, so you could for instance have a common error message. And it’s probably less error-prone; hard to err in calling the verify method. Nonetheless, it adds an extra layer of abstraction, and extra layers of abstraction should not be added lightly. So I’m still sticking with the first version.
Fantasy-land possibilities
So much for reality, how tedious. Here’s how I would like it to be done. If Java had closures - and CSharp’s anonymous method shows it’s feasible - you could call a verify method something like this:
verifyExceptionThrown({map.locateCoordinates("Alpha Centauri")}); // I'm making up the syntax!
More realistically, JUnit’s reflection could quite easily be altered to let you declare a test method throws an exception:
public void testGettingCoordinatesOfFarawayStarThrowsOutOfBoundsException() {
map.locateCoordinates("Alpha Centauri")
}
This way, by merely following the common wisdom that test methods should be self-documenting, JUnit will be able to use reflection to check that what kind of exception is thrown.
Well, maybe JBehave with its various hooks might be suited to this sort of thing.
Caveat: Sometimes You Want to Verify the Exception
Some of the above would need further modification if you are concerned about verifying details of the exception in the catch block, e.g.:
assertTrue(ex.getMessage(“Whew! That’s a bit far, what are you gonna do? Teleport yourself?!”))
In practice, there’s not too much value in doing that too often: messages are fragile, and even for other exception information, you possibly only want to check it once or twice. The rest of the time, you probably just want to know the right type of exception was thrown.