Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bad form for JUnit test to throw exception?

People also ask

Should JUnit tests throw exceptions?

The JUnit TestRunners will catch the thrown Exception regardless so you don't have to worry about your entire test suite bailing out if an Exception is thrown. This is the best answer.

How do you write a test case for throwing a new exception in JUnit?

In order to test the exception thrown by any method in JUnit 4, you need to use @Test(expected=IllegalArgumentException. class) annotation. You can replace IllegalArgumentException. class with any other exception e.g. NullPointerException.

What happens if a test method throws an exception?

Yes it is completely fine, and if it does throw the exception the test will be considered as failed. You need to specify that the method throws an Exception even if you know that the specific case does not (this check is done by the compiler).


Actually, the old style of exception testing is to wrap a try block around the code that throws the exception and then add a fail() statement at the end of the try block. Something like this:

public void testNullParameter() {
    try {
        IPAddress addr = new IPAddress(null);
        fail("InvalidIPAddressException not thrown.");
    } catch(InvalidIPAddressException e) {
        assertNotNull(e.getMessage());
    }
}

This isn't much different from what you wrote but:

  1. Your assertTrue(addr.getOctets() == null); is useless.
  2. The intend and the syntax are clearer IMO and thus easier to read.

Still, this is a bit ugly. But this is where JUnit 4 comes to the rescue as exception testing is one of the biggest improvements in JUnit 4. With JUnit 4, you can now write your test like this:

@Test (expected=InvalidIPAddressException.class) 
public void testNullParameter() throws InvalidIPAddressException {
    IPAddress addr = new IPAddress(null);
}

Nice, isn't it?

Now, regarding the real question, if I don't expect an exception to be thrown, I'd definitely go for way #1 (because it's less verbose) and let JUnit handle the exception and fail the test as expected.


For tests where I don't expect an exception, I don't bother to catch it. I let JUnit catch the exception (it does this reliably) and don't cater for it at all beyond declaring the throws cause (if required).

I note re. your first example that you're not making use of the @expected annotation viz.

@Test (expected=IndexOutOfBoundsException.class) public void elementAt() {
    int[] intArray = new int[10];

    int i = intArray[20]; // Should throw IndexOutOfBoundsException
  }

I use this for all tests that I'm testing for throwing exceptions. It's briefer than the equivalent catch/fail pattern that I had to use with Junit3.


Since JUnit 4.7 you have the possibility to use an ExpectedException rule and you should use it. The rule gives you the possibility to define exactly the called method where the exception should be thrown in your test code. Moreover, you can easily match a string against the error message of the exception. In your case the code looks like this:

    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    @Test
    public void test() {
        //working code here...
        expectedException.expect(InvalidIPAddressException.class);
        IPAddress addr = new IPAddress(null);
    }

UPDATE: In his book Practical Unit Testing with JUnit and Mockito Tomek Kaczanowski argues against the use of ExpectedException, because the rule "breaks the arrange/act/assert [...] flow" of a Unit test (he suggests to use Catch Exception Library instead). Although I can understand his argument, I think using the rule is fine if you do not want to introduce another 3rd-party library (using the rule is better than catching the exception "manually" anyway).