0

I'm writing a JUnit/Mockito test where an exception is expected to be thrown. Of course I can just do this:

@Test(expected=IllegalArgumentException.class)

But it doesn't let me to do anything else after it was thrown. So I was thinking maybe something more like:

Exception actualEx = null;
try {
    // Act
    sut.doStuff();
} catch (final Exception ex) {
    actualEx = ex;
}
// Assert
assertTrue(IllegalArgumentException.class.equals(actualEx.getClass()));
// ... perhaps verify the exception details
verifyNoMoreInteractions(mockObject);

This seems pretty ugly and feels like it could be improved - is there a better way?

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
  • 3
    Have you tried the ExpectedException rule? http://alexruiz.developerblogs.com/?p=1530 – luanjot Nov 19 '13 at 08:56
  • or [catch-exception](https://code.google.com/p/catch-exception/), too bad however they use FEST-Assert (almost dead) instead of AssertJ – bric3 Nov 19 '13 at 09:30
  • @Brice Thanks but would prefer to avoid add-on libraries if I can help it... – Steve Chambers Nov 19 '13 at 09:41
  • I understand (I'm still not a fan of adding Nth libraries), though catch-exception is enable us to follow Arrange/Act/Assert or BDD principles in test which is more interesting regarding the readability of the test. – bric3 Nov 19 '13 at 20:43
  • An alternative duplicate with answers that also cover JUnit5's `AssertThrows`: [How do you assert that a certain exception is thrown in JUnit 4 tests?](https://stackoverflow.com/questions/156503) – Steve Chambers Sep 18 '19 at 10:34

3 Answers3

2

I think you should be consistent throughout your project - although there are three or four different ways to solve this problem, you absolutely should not try to use all of them.

Since the ExpectedException mechanism is the most powerful and most versatile way, I would recommend you learn to use it. Its advantages include the following.

  • It's easy to check both the type of the thrown exception and its message.
  • You can do more sophisticated matching on the exception if you need to.
  • You can check exactly which line of your test throws the exception, by placing the expect call immediately before the line that you expect to throw the exception.

At the risk of sounding like a shampoo advertisement - now that I've used ExpectedException, I wouldn't use anything else!

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
1

There is no best way. It depends :-) Take a look at the JUnit Wiki: https://github.com/junit-team/junit/wiki/Exception-testing

Stefan Birkner
  • 24,059
  • 12
  • 57
  • 72
1

Just an add-on here. I agree with Stefan's post and that is a good resources. Here are the guidelines I follow.

  1. I only use the @Test(expected=...) if there is only one method call in the test and that is the method under test. That is because of the following... what if you have @Test(expect=NullPointerException.class) and you have a bug somewhere in the setup of the test that throws this exception. The test will pass having never called the method under test.

  2. So, in all other cases I use the ExpectedException Rule with the expect immediately before the call to the method under test. In this way if an exception is thrown in the code prior to the method call the test will fail.

I never use the catch / fail mechanism because it is too easy for someone inexperienced to remove the fail and this would allow the test to pass erroneously. If I need to do extra verification I still use ExpectedException and rethrow the exception inside the catch block after I have done any additional verification.

John B
  • 32,493
  • 6
  • 77
  • 98