Möchte man das auftreten von Exceptions mit JUnit testen, so gibt es verschiedene Wege und Möglichkeiten. Die bekanntesten sind sicherlich
@Test(expected=IllegalArgumentException.class)
public void methodThrowsException() {
subjectUnderTest.foo(someIllegalArgument);
}
und
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void methodThrowsException() {
thrown.expect(IllegalArgumentException.class);
subjectUnderTest.foo(someIllegalArgument);
}
Beide Varianten haben den Nachteil, dass die Given-When-Then (oder Arrange-Act-Assert) Reihenfolge aufgebrochen wird, so dass man häufig „von Hand“ geschriebenen Code wie den folgenden findet:
@Test
public void methodThrowsException() {
try {
subjectUnderTest.foo(someIllegalArgument);
fail("IllegalArgumentException expected, but not thrown!");
} catch (IllegalArgumentException ex) {
assertThat(ex.getMessage(), is("foobarfoo"));
}
}
Jetzt sind die Anweisungen zwar wieder in der Given-When-Then Reihenfolge, aber die try-catch-Anweisungen machen den Code unübersichtlich.
Die folgende Lösung ist uns in den Sinn gekommen, nachdem wir uns im aktuellen Projekt über Clean Code ausgetauscht haben:
@Test
public void methodThrowsException() {
IllegalArgumentException ex = foo(someIllegalArgument);
assertThat(ex.getMessage(), is("foobarfoo"));
}
private Exception foo(FooBarFoo fooBarFoo) {
try {
subjectUnderTest.foo(someIllegalArgument);
return null;
} catch (IllegalArgumentException ex) {
return ex;
}
}
Der Testcode ist sauber, die Reihenfolge der Testanweisungen stimmt und es sind keine Erweiterungen wie @Rules oder catch-excpetion notwendig.