How can I test several exceptions within one test using an ExpectedException Rule?
Asked Answered
M

1

7

Got a question regarding the usage of junit's ExpectedException rule:

As suggested here: junit ExpectedException Rule starting from junit 4.7 one can test exceptions like this (which is much better then the @Test(expected=Exception.class)):

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

@Test
public void testFailuresOfClass() {
 Foo foo = new Foo();
 exception.expect(Exception.class);
 foo.doStuff();
}

Now I needed to test several exceptions in one test method and got a green bar after running the following test and thus thought every test passed.

@Test
public void testFailuresOfClass() {
 Foo foo = new Foo();

 exception.expect(IndexOutOfBoundsException.class);
 foo.doStuff();

 //this is not tested anymore and if the first passes everything looks fine
 exception.expect(NullPointerException.class);
 foo.doStuff(null);

 exception.expect(MyOwnException.class);
 foo.doStuff(null,"");

 exception.expect(DomainException.class);
 foo.doOtherStuff();
}

However after a while I realized that the testmethod is quit after the first check passes. This is ambiguous to say the least. In junit 3 this was easily possible... So here is my question:

How can I test several exceptions within one test using an ExpectedException Rule?

Meningitis answered 18/7, 2013 at 11:19 Comment(2)
You can still use the Junit 3 way, but it's not possible using the @Test(expected) nor the ExpectedException.Squilgee
It's not that bad. Usually it's better to test one thing per test anyway. It's okay if you test for, say notNull, size and contents for a list in the same test, but don't test two conceptual different things in one test. It's less readable. If you test one thing per test, you can use the method name to describe what your are testing, instead of 'testException'Squilgee
E
6

Short answer: You can't.

If the first call - to foo.doStuff() - throws an exception, you will never reach foo.doStuff(null). You'll have to split your test up into several (and for this trivial case I'd propose going back to the simple notation, without ExpectedException):

private Foo foo;

@Before 
public void setUp() {
 foo = new Foo();
}

@Test(expected = IndexOutOfBoundsException.class)
public void noArgsShouldFail() {
 foo.doStuff();
}

@Test(expected = NullPointerException.class)
public void nullArgShouldFail() {
 foo.doStuff(null);
}

@Test(expected = MyOwnException.class)
public void nullAndEmptyStringShouldFail() {
 foo.doStuff(null,"");
}

@Test(expected = DomainException.class)
public void doOtherStuffShouldFail() {
 foo.doOtherStuff();
}

If you really want one and only one test, you can fail if no error is thrown, and catch the things you expect:

@Test
public void testFailuresOfClass() {
 Foo foo = new Foo();

 try {
    foo.doStuff();
    fail("doStuff() should not have succeeded");
 } catch (IndexOutOfBoundsException expected) {
    // This is what we want.
 }
 try {
    foo.doStuff(null);
    fail("doStuff(null) should not have succeeded");
 } catch (NullPointerException expected) {
    // This is what we want.
 }
 // etc for other failure modes
}

This gets quite messy pretty fast, though, and if the first expectation fails, you won't see if anything else fails as well, which can be annoying when troubleshooting.

Elston answered 18/7, 2013 at 11:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.