Search This Blog

Testing for exceptions in JUnit revised

In his recent post the author of fantastic mocking framework Mockito collected few rules about testing exceptions. What caught my attention is the advice to use JUnit rules (nomen est omen!) for testing exceptions. ExpectedException rule gathers advantages of both expected@Test attribute clarity and try-catch strictness. Here is the example:

Szczepan claims that ExpectedException fits into given/when/then test template nicely. I disagree! Look at the code snippet above – what is the most natural place to put assertions on exception being thrown? From the obvious reasons it must be the last line before the line that actually throws the exceptions. So you have a choice to put assertion as the last statement in given block or as first in when block. You are right, this is how this test should look like in an ideal world:

No we’re talking! There’s just this tiny problem with example above – we expect code in when block to throw an exception and put assertions afterwards in then block. See the problem? If we could somehow transparently catch the exception, store it somewhere, return normally and let assertions to run against it... With AOP it is actually pretty easy, but I wanted to implement this feature using pure Java and with JUnit framework. First, I will introduce @UnderTest marker annotation:

Now put this annotation above the field in your test case corresponding to class under test:

@UnderTest
private FooService fooService = new DefaultFooService();

Although the annotation brings some value itself, marking which object is actually being tested, it is not meant for documentation and test readability, I am going to use it together with some Java reflection. I mentioned that AOP would solve our problems. JUnit 4.7 ships with AOP-like mechanism called rules. By writing a rule (ExpectedException is an example of a JUnit built-in rule) you simply create an interceptor around every test method. With this interceptor you can, for instance, run test method in separate thread, do some setup and cleanup, etc. My custom rule will do two things:

wrap class under test in Java proxy to catch every exception, store it and return normally

First test method does not expect any exception to be thrown – it if will, test will fail. Second test expects NullPointerException. Please note that if the exception will be thrown from any other line than fooService.echo() (or fooService.echo() won’t throw NullPointerException), test will fail. The last test shows that you can also assert exception message as well.

Few things are still missing in 0.0.1 "version", mainly proxying classes (CGLIB, anyone?); also, some syntactic sugar together with DSL-like (FEST-like) assertions could be introduced:

Also I had to copy&paste big parts of JUnit’s ExpectedException, as most obvious inheritance was not possible due to private constructor. But still, take a look at ExceptionAssert rule and see for yourself how readable exception testing can be. As always, source code can be cloned and downloaded from my GitHub account. Any comments and contributions are welcome!