You are here

Expecting Exceptions

Most test tools provide the developer with means to suggest that a test should expect an specific exception. For instance, JUnit the prevalent test tool for the Java language provides an annotation to mark such a test (from the JUnit 4 documentation):

    public void empty() {
         new ArrayList<Object>().get(0);

The annotation marks the method as a test and the parameter “expected” tells JUnit which exception type to expect.

Recently I stumbled about some test code from a co-worker who did the tests for expected exceptions a little different:

    public void emptyToo() {
        try {
            new ArrayList<Object>().get(0);
        catch (IndexOutOfBoundsException e) {
        catch (Exception e) {
  "Wrong Exception raised: " + e);
        }"No Exception raised.");

This code does the same as the first one. I asked him why he did it this way instead of the more succinct “canonical” way. I thought maybe he does not know about it. But his answer baffled me.

He argued that tests are living documentation of the usage of the system under test. If somebody would come to this test to see which exceptions it would throw under which circumstances they could use his test code as a template for how to deal with the exceptions. In extreme cases they could even copy the test code verbatim, more or less, if they needed to catch the exceptions at this level.

I have never seen it this way. He is right somehow. There is one thing which bothers me with this solution though. The actual exercise of the system under test is buried deeply inside the try/catch construct. Tests are supposed to be easy to read, but in this case it is not immediately obvious what this test is doing. I would rather have the test tell me right away that it is asserting that an exception is raised when the system under test is exercised with the current setup. The canonical version is explicit about that. Before I even get to read the method name I will know that it is expecting an IndexOutOfBoundsException. The reader of the method will know it and, which is important too, the test framework will know it. The calls do not really tell the story of the test in a way JUnit can understand. It only sees that some test failure occurred.

Still I like the idea. This might be useful for more complex integration tests...