8

Instead of doing Exception-handling in my JUnit tests, I just declare my test-methods with ... throws Exception?

I started doing that and I don't see a reason why I should be more specific.

codepleb
  • 10,086
  • 14
  • 69
  • 111

2 Answers2

14

The core aspect of unit-tests is to help you isolate / resolve bugs in your production code as quickly as possible.

In that sense: you do not write your @Test methods in order to be called by other methods. You write them so that the JUnit framework runs them.

And typically, when that test throws an exception; there is no point in catching that (unless it is expected; and you want to do further checking on that exception).

Thus: not having catch blocks; and instead adding potential throw causes to your test method signatures is the correct answer in 99.999% of all cases. Or maybe 100%; as I can't find a good counter example.

But I would be careful though about using throws Exception to quickly. You still want your code to be as "specific" as possible; so better go for throws ThatExceptionThatCanReallyBeThrown. And when that list grows too lengthy too often ... then you better follow up on that side and check if your throws list in your production code should be "trimmed" down somehow.

Edit: probably the core thing to understand is: for each any any of your tests, you have an exact expectation towards what will happen. That method should either:

  1. Not throw an exception
  2. Throw a specific exception (then you would do @Test(expected=...) thing
  3. Throw a specific exception ... which your test needs to catch for further checking
  4. Throw an exception ... which would then indicate a real "error" condition (because you didn't expect it to happen); and in that case JUnit will catch the exception and report it to you as failed testcase. (But of course, keep in mind that there is a subtle difference a testcase error and a test failure in JUnit).

And just putting throws X, Y on your test method signature is the straight forward way of addressing bullets 2 and 4.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • I would be interested in one of those 1% cases, where it would be bad practice. – codepleb Dec 12 '16 at 14:20
  • 2
    I guess: that would be the cases when you expect some exception to happen and you need to further check properties of the caught exception object. Otherwise, you would actually just put `@Test(expected=Whatever.class)` on your method ... and have Whatever on your throws list. – GhostCat Dec 12 '16 at 14:21
  • Ok. So basically if you implement custom Exceptions that you wan't to check. Sounds reasonable. :) Thank you – codepleb Dec 12 '16 at 14:24
  • 1
    i think the 99% caveat is too cautious here. really there is no good reason, except to make tools like sonarqube happy. – Nathan Hughes Dec 12 '16 at 14:26
  • @NathanHughes You are probably correct ... I rephrased that part as well. – GhostCat Dec 12 '16 at 14:29
  • 2
    Some of my colleagues tend to prefer `throws Exception` over `throws ThisExceprtion, ThatException, TheOtherException` so they don’t have to change the throws clause when production code evolves. While I prefer the more specific, I have a hard time really blaming them. – Ole V.V. Dec 12 '16 at 14:40
  • 1
    @OleV.V. You should also ask yourself what you want to test: either the API and the promised behaviour or implementations details. And `throws BlubException` is an implementation detail. And as your colleagues say, then you test implementation details, you'll have to adjust your tests every time you change your code. – Tom Dec 12 '16 at 14:43
  • JUnit distiguishes between failures and errors. See [What's the difference between failure and error in JUnit?](http://stackoverflow.com/questions/3425995/whats-the-difference-between-failure-and-error-in-junit) If for some reason you prefer to see your unexpected exceptions as test failures, you will need to catch the exception and declare a failure (with `fail()`). – Ole V.V. Dec 12 '16 at 14:43
  • @OleV.V. Helpful information, in deed. I added the failure/error thing to my answer. – GhostCat Dec 12 '16 at 14:53
4

In addition to @GhostCat answer want to say - JUnit has nice feature named Rules. It is well suited for testing exceptions and maybe better than @Test(expected=Whatever.class).

Example usage:

public class Test {
  @Rule
  public final ExpectedException thrown = ExpectedException.none();

  private MyService myService;

  @Before
  public void setUp() {
    myService = new MyService ();
  }
  @Test
  public void exceptionTest() throws MyException {
    thrown.expect(MyException.class);
    thrown.expectMessage("my description");
    myService.create("bad argument"); //throws MyException("my description")
  }
}
David Conrad
  • 15,432
  • 2
  • 42
  • 54
Sergey Morozov
  • 4,528
  • 3
  • 25
  • 39