views:

1121

answers:

4

Is it possible to test for multiple exceptions in a single JUnit unit test? I know for a single exception one can use, for example

    @Test(expected=IllegalStateException.class)

Now, if I want to test for another exception (say, NullPointerException), can this be done in the same annotation, a different annotation or do I need to write another unit test completely?

A: 

How would you expect to "expected"s to work? A method can only throw one exception.

You would have to write a different unit test for each way the method can fail. So if the method legitimately throw two exceptions then you need two tests set up to force the method of throwing each exception.

mlk
A method can only throw one exception, but can be declared as throwing many different exceptions. Say that a method can throw 4 exception types, throwing either A or B passes the test, throwing C or D fails the test. This would be easy is 'expected' tool an array of classes instead of a single class
Glen
But under one set of data is can only fail in one way.
mlk
+3  A: 

You really want the test to do one thing, and to test for that. If you're not sure as to which exception is going to be thrown, that doesn't sound like a good test to me.

e.g. (in pseudo-code)

try {
   badOperation();
   /// looks like we succeeded. Not good! Fail the test
}
catch (ExpectedException e) {
   // that's fine
}
catch (UnexpectedException e) {
   // that's NOT fine. Fail the test
}

so if you want to test that your method throws 2 different exceptions (for 2 sets of inputs), then you'll need 2 tests.

Brian Agnew
I usually call fail() within the try block, immediately after badOperation().
Yuval
At any given point I am sure which statement I expect to throw an error. In one test, I wish to test that all expected exceptions gets thrown. I'll be honest, I'm not thrilled about the annotation way of testing for exceptions: a bad test may cause an expected exception at an unexpected point in the test. In that sense I favour the try-catch-fail of testing for an exception, but just looks ugly. I suppose you are right in a sense, though: my tests should be more atomic (rather than testing everything for one method in a single unit test, as I am trying to do).
phantom-99w
@Yuval - I was trying to be test-framework agnostic in the above. However I've amended to be clearer.
Brian Agnew
@Phantom - atomicity for tests can be a pain, but I believe that's the way forward, and reduces ambiguity when your tests fail. I have written tests that check for multiple exceptions though by not using annotations and nesting tests within the catch blocks of preceeding tests. After a while it gets a bug ugly...
Brian Agnew
The "catch (UnexpectedOperation e)" is unnecessary; if a test method throws an exception, that's considered a failure. As Yuval mentioned, you need to do a fail() immediately after badOperation()
NamshubWriter
@NamshubWriter - you're missing the point. The above is pseudo-code illustrating when you need to take action.
Brian Agnew
Sorry for downvoting, it happened by accident ... stackoverflow wont let me change my vote unless you edit your post.
Adrian
@Adrian - you can just click on the down arrow again to reset...
Brian Agnew
@Brain - I cannot, it complains "Vote to old to be changed, unless this answer is edited"
Adrian
@Adrian - now edited!
Brian Agnew
A: 

keep the tests as simple and short as possible. the intention of a JUnit-Test is to test only one simple functionality or one single way of failure.

indeed, to be safe, you should create at least one test for every possible execution way.

normally, this is not always possible because if you have a method that analyzes a string, there are so many possible string combinations that you cannot cover everything.

keep it short and simple.

you can have 30-40 testing methods for one single method easily... does it really matter?

regards

Atmocreations
A: 

This is not possible with the annotation.

With JUnit 4.7 you can use the new ExpectedException rule

public static class HasExpectedException {
    @Interceptor
    public ExpectedException thrown= new ExpectedException();

    @Test
    public void throwsNothing() {
    }

    @Test
    public void throwsNullPointerException() {
         thrown.expect(NullPointerException.class);
         throw new NullPointerException();
    }

    @Test
    public void throwsNullPointerExceptionWithMessage() {
        thrown.expect(NullPointerException.class);
        thrown.expectMessage("happened?");
        throw new NullPointerException("What happened?");
    }
}

More see


If updating to JUnit 4.7 is not possible for you, you have to write a bare unit test of the form

public test() {
    try {
        methodCall(); // should throw Exception
        fail();
    }
    catch (Exception ex) {
        assert((ex instanceof A) || (ex instanceof B) || ...etc...);
        ...
    }

}

Adrian