Thursday, May 19, 2005

Failing Tests

Four approaches to writing a test that expects an exception to occur:

  • Approach 1:
    public void failGetter() throws IllegalArgumentException { 
    new Foo(null).getMember();
    }

  • Approach 2:
    public void testGetter2() { 
    String msg = ThrowAssert.assertThrows(IllegalArgumentException.class, new Block() {
    public void call() throws Exception {
    new Foo(null).getMember();
    }
    });
    }

  • Approach 3:
    public void testGetter3() { 
    Foo foo = new Foo(null);
    String msg = ThrowAssert.assertThrows(IllegalArgumentException.class, foo,
    new CallSpec("getMember", new Class[]{}, new Object[] {null}));
    }

  • Approach 4:
    public void testGetter4() { 
    try {
    new Foo(null).getMember();
    fail("Expected NPE");
    } catch (NullPointerException npe) {
    // We expect this to happen.
    } catch (Exception e) {
    fail("Wrong exception thrown");
    }
    }


I generally prefer Approach 2 because it is more extensible, use it when:

  • There are multiple assertions to be checked and complicated calling is expected.

  • Multiple exceptions are thrown, you can ignore any exception including checked exceptions.

  • Assertions need to be made on the message from the thrown exception.

  • There needs to be an opposing assertion - a test that it doesn't throw an exception (assertPasses).

  • Variables can be made final.


Approach 1 can be used when the intent and code can be expressed on one line and only one exception is expected. It also requires there to be a bit of code in a test base class although it is inconsistent with the usual "textXXX" method names used for test code.

No comments: