Se si sta utilizzando l'ultima versione di JUnit è possibile estendere il test runner di default per gestire questo per voi (senza dover avvolgere ciascuno dei vostri metodi in un blocco try/catch)
ExtendedTestRunner.java - nuovo test runner:
public class ExtendedTestRunner extends BlockJUnit4ClassRunner
{
public ExtendedTestRunner(Class<?> clazz)
throws InitializationError
{
super(clazz);
}
@Override
protected Statement possiblyExpectingExceptions(FrameworkMethod method,
Object test,
Statement next)
{
ExtendedTest annotation = method.getAnnotation(ExtendedTest.class);
return expectsCauseException(annotation) ?
new ExpectCauseException(next, getExpectedCauseException(annotation)) :
super.possiblyExpectingExceptions(method, test, next);
}
@Override
protected List<FrameworkMethod> computeTestMethods()
{
Set<FrameworkMethod> testMethods = new HashSet<FrameworkMethod>(super.computeTestMethods());
testMethods.addAll(getTestClass().getAnnotatedMethods(ExtendedTest.class));
return testMethods;
}
@Override
protected void validateTestMethods(List<Throwable> errors)
{
super.validateTestMethods(errors);
validatePublicVoidNoArgMethods(ExtendedTest.class, false, errors);
}
private Class<? extends Throwable> getExpectedCauseException(ExtendedTest annotation)
{
if (annotation == null || annotation.expectedCause() == ExtendedTest.None.class)
return null;
else
return annotation.expectedCause();
}
private boolean expectsCauseException(ExtendedTest annotation) {
return getExpectedCauseException(annotation) != null;
}
}
ExtendedTest.java - annotazione per contrassegnare i metodi di prova con:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ExtendedTest
{
/**
* Default empty exception
*/
static class None extends Throwable {
private static final long serialVersionUID= 1L;
private None() {
}
}
Class<? extends Throwable> expectedCause() default None.class;
}
ExpectCauseException.java - nuova dichiarazione JUnit:
public class ExpectCauseException extends Statement
{
private Statement fNext;
private final Class<? extends Throwable> fExpected;
public ExpectCauseException(Statement next, Class<? extends Throwable> expected)
{
fNext= next;
fExpected= expected;
}
@Override
public void evaluate() throws Exception
{
boolean complete = false;
try {
fNext.evaluate();
complete = true;
} catch (Throwable e) {
if (e.getCause() == null || !fExpected.isAssignableFrom(e.getCause().getClass()))
{
String message = "Unexpected exception cause, expected<"
+ fExpected.getName() + "> but was<"
+ (e.getCause() == null ? "none" : e.getCause().getClass().getName()) + ">";
throw new Exception(message, e);
}
}
if (complete)
throw new AssertionError("Expected exception cause: "
+ fExpected.getName());
}
}
Usage:
@RunWith(ExtendedTestRunner.class)
public class MyTests
{
@ExtendedTest(expectedCause = MyException.class)
public void someMethod()
{
throw new RuntimeException(new MyException());
}
}
poco importante side-nota: si "aspetta = ...", non "aspettarsi = ..." – hoijui
Non posso credere che JUnit 5 a quanto pare non ha aumentato la sua sintassi di annotazione di includere Questo. –