How to verify that an exception was not thrown

Another approach might be to use try/catch instead. It's a bit untidy but from what I understand this test is going to be short-lived anyway as it's for TDD:

@Test
public void testNPENotThrown{
  Calling calling= Mock(Calling.class);
  testClass.setInner(calling);
  testClass.setThrow(true);

  try{
    testClass.testMethod();
    fail("NPE not thrown");
  }catch (NullPointerException e){
    //expected behaviour
  }
}

EDIT: I was in a hurry when I wrote this. What I mean by 'this test is going to be short-lived anyway as it's for TDD' is that you say you are going to write some code to fix this test straight away, so it will never throw a NullPointerException in the future. Then you might as well delete the test. Consequently it's probably not worth spending a lot of time writing a beautiful test (hence my suggestion :-))

More generally:

Starting off with a test to assert that (for example) the return value of a method is not null is an established TDD principle, and checking for a NullPointerException (NPE) is one possible way of going about this. However your production code is presumably not going to have a flow where a NPE is thrown. You are going to check for null and then do something sensible, I imagine. That would make this particular test redundant at that point as it will be checking an NPE is not thrown, when in fact it can never happen. You might then replace it with a test which verifies what does happen when a null is encountered: returns a NullObject for example, or throws some other type of exception, whatever is appropriate.

There is of course no requirement that you delete the redundant test, but if you don't, it will sit there making each build slightly slower, and causing each developer who reads the test to wonder; "Hmm, an NPE? Surely this code can't throw an NPE?". I have seen a lot of TDD code where the test classes have a lot of redundant tests like this. If time permits it pays to review your tests every so often.


If I dont understand you wrong you need something like this:

@Test(expected = NullPointerException.class)
public void testNPENotThrown {
    Calling calling= Mock(Calling .class);
    testClass.setInner(calling);
    testClass.setThrow(true);

    testClass.testMethod();

    verify(calling, never()).method();
    Assert.fail("No NPE");
}

but by the naming of the test "NPENotThrown" I would expect a test like this:

public void testNPENotThrown {
    Calling calling= Mock(Calling .class);
    testClass.setInner(calling);
    testClass.setThrow(true);

    testClass.testMethod();
    try {
        verify(calling, never()).method();
        Assert.assertTrue(Boolean.TRUE);
    } catch(NullPointerException ex) {
        Assert.fail(ex.getMessage());
    }
}

tl;dr

  • post-JDK8 : Use AssertJ or custom lambdas to assert exceptional behaviour.

  • pre-JDK8 : I will recommend the old good try-catch block. (Don't forget to add a fail() assertion before the catch block)

Regardless of Junit 4 or JUnit 5.

the long story

It is possible to write yourself a do it yourself try-catch block or use the JUnit tools (@Test(expected = ...) or the @Rule ExpectedException JUnit rule feature).

But these ways are not so elegant and don't mix well readability wise with other tools. Moreover, JUnit tooling does have some pitfalls.

  1. The try-catch block you have to write the block around the tested behavior and write the assertion in the catch block, that may be fine but many find that this style interrupts the reading flow of a test. Also, you need to write an Assert.fail at the end of the try block. Otherwise, the test may miss one side of the assertions; PMD, findbugs or Sonar will spot such issues.

  2. The @Test(expected = ...) feature is interesting as you can write less code and then writing this test is supposedly less prone to coding errors. But this approach is lacking in some areas.

    • If the test needs to check additional things on the exception like the cause or the message (good exception messages are really important, having a precise exception type may not be enough).
    • Also as the expectation is placed around in the method, depending on how the tested code is written then the wrong part of the test code can throw the exception, leading to false-positive test and I'm not sure that PMD, findbugs or Sonar will give hints on such code.

      @Test(expected = WantedException.class)
      public void call2_should_throw_a_WantedException__not_call1() {
          // init tested
          tested.call1(); // may throw a WantedException
      
          // call to be actually tested
          tested.call2(); // the call that is supposed to raise an exception
      }
      
  3. The ExpectedException rule is also an attempt to fix the previous caveats, but it feels a bit awkward to use as it uses an expectation style, EasyMock users know very well this style. It might be convenient for some, but if you follow Behaviour Driven Development (BDD) or Arrange Act Assert (AAA) principles the ExpectedException rule won't fit in those writing style. Aside from that it may suffer from the same issue as the @Test way, depending on where you place the expectation.

    @Rule ExpectedException thrown = ExpectedException.none()
    
    @Test
    public void call2_should_throw_a_WantedException__not_call1() {
        // expectations
        thrown.expect(WantedException.class);
        thrown.expectMessage("boom");
    
        // init tested
        tested.call1(); // may throw a WantedException
    
        // call to be actually tested
        tested.call2(); // the call that is supposed to raise an exception
    }
    

    Even the expected exception is placed before the test statement, it breaks your reading flow if the tests follow BDD or AAA.

    Also, see this comment issue on JUnit of the author of ExpectedException. JUnit 4.13-beta-2 even deprecates this mechanism:

    Pull request #1519: Deprecate ExpectedException

    The method Assert.assertThrows provides a nicer way for verifying exceptions. In addition, the use of ExpectedException is error-prone when used with other rules like TestWatcher because the order of rules is important in that case.

So these above options have all their load of caveats, and clearly not immune to coder errors.

  1. There's a project I became aware of after creating this answer that looks promising, it's catch-exception.

    As the description of the project says, it let a coder write in a fluent line of code catching the exception and offer this exception for the latter assertion. And you can use any assertion library like Hamcrest or AssertJ.

    A rapid example taken from the home page :

    // given: an empty list
    List myList = new ArrayList();
    
    // when: we try to get the first element of the list
    when(myList).get(1);
    
    // then: we expect an IndexOutOfBoundsException
    then(caughtException())
            .isInstanceOf(IndexOutOfBoundsException.class)
            .hasMessage("Index: 1, Size: 0") 
            .hasNoCause();
    

    As you can see the code is really straightforward, you catch the exception on a specific line, the then API is an alias that will use AssertJ APIs (similar to using assertThat(ex).hasNoCause()...). At some point the project relied on FEST-Assert the ancestor of AssertJ. EDIT: It seems the project is brewing a Java 8 Lambdas support.

    Currently, this library has two shortcomings :

    • At the time of this writing, it is noteworthy to say this library is based on Mockito 1.x as it creates a mock of the tested object behind the scene. As Mockito is still not updated this library cannot work with final classes or final methods. And even if it was based on Mockito 2 in the current version, this would require to declare a global mock maker (inline-mock-maker), something that may not what you want, as this mock maker has different drawbacks that the regular mock maker.

    • It requires yet another test dependency.

    These issues won't apply once the library supports lambdas. However, the functionality will be duplicated by the AssertJ toolset.

    Taking all into account if you don't want to use the catch-exception tool, I will recommend the old good way of the try-catch block, at least up to the JDK7. And for JDK 8 users you might prefer to use AssertJ as it offers may more than just asserting exceptions.

  2. With the JDK8, lambdas enter the test scene, and they have proved to be an interesting way to assert exceptional behaviour. AssertJ has been updated to provide a nice fluent API to assert exceptional behaviour.

    And a sample test with AssertJ :

    @Test
    public void test_exception_approach_1() {
        ...
        assertThatExceptionOfType(IOException.class)
                .isThrownBy(() -> someBadIOOperation())
                .withMessage("boom!"); 
    }
    
    @Test
    public void test_exception_approach_2() {
        ...
        assertThatThrownBy(() -> someBadIOOperation())
                .isInstanceOf(Exception.class)
                .hasMessageContaining("boom");
    }
    
    @Test
    public void test_exception_approach_3() {
        ...
        // when
        Throwable thrown = catchThrowable(() -> someBadIOOperation());
    
        // then
        assertThat(thrown).isInstanceOf(Exception.class)
                          .hasMessageContaining("boom");
    }
    
  3. With a near-complete rewrite of JUnit 5, assertions have been improved a bit, they may prove interesting as an out of the box way to assert properly exception. But really the assertion API is still a bit poor, there's nothing outside assertThrows.

    @Test
    @DisplayName("throws EmptyStackException when peeked")
    void throwsExceptionWhenPeeked() {
        Throwable t = assertThrows(EmptyStackException.class, () -> stack.peek());
    
        Assertions.assertEquals("...", t.getMessage());
    }
    

    As you noticed assertEquals is still returning void, and as such doesn't allow chaining assertions like AssertJ.

    Also if you remember name clash with Matcher or Assert, be prepared to meet the same clash with Assertions.

I'd like to conclude that today (2017-03-03) AssertJ's ease of use, discoverable API, the rapid pace of development and as a de facto test dependency is the best solution with JDK8 regardless of the test framework (JUnit or not), prior JDKs should instead rely on try-catch blocks even if they feel clunky.