Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 882
Lonzak Avatar asked Jul 18 '13 11:07

Lonzak


1 Answers

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.

like image 178
gustafc Avatar answered Sep 20 '22 14:09

gustafc