Is there a way in JUnit to detect within an @After annotated method if there was a test failure or error in the test case?
One ugly solution would b
I extend dsaff's answer to solve the problem that a TestRule
can not execute some code snipped between the execution of the test-method and the after-method. So with a simple MethodRule
one can not use this rule to provide a success flag that is use in the @After
annotated methods.
My idea is a hack! Anyway, it is to use a TestRule
(extends TestWatcher
). A TestRule
will get knowledge about failed or success of a test. My TestRule
will then scan the class for all Methods annotated with my new AfterHack
annotations and invoke that methods with a success flag.
AfterHack
annotation
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
public @interface AfterHack {}
AfterHackRule
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
public class AfterHackRule extends TestWatcher {
private Object testClassInstance;
public AfterHackRule(final Object testClassInstance) {
this.testClassInstance = testClassInstance;
}
protected void succeeded(Description description) {
invokeAfterHackMethods(true);
}
protected void failed(Throwable e, Description description) {
invokeAfterHackMethods(false);
}
public void invokeAfterHackMethods(boolean successFlag) {
for (Method afterHackMethod :
this.getAfterHackMethods(this.testClassInstance.getClass())) {
try {
afterHackMethod.invoke(this.testClassInstance, successFlag);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
throw new RuntimeException("error while invoking afterHackMethod "
+ afterHackMethod);
}
}
}
private List getAfterHackMethods(Class> testClass) {
List results = new ArrayList<>();
for (Method method : testClass.getMethods()) {
if (method.isAnnotationPresent(AfterHack.class)) {
results.add(method);
}
}
return results;
}
}
Usage:
public class DemoTest {
@Rule
public AfterHackRule afterHackRule = new AfterHackRule(this);
@AfterHack
public void after(boolean success) {
System.out.println("afterHack:" + success);
}
@Test
public void demofails() {
Assert.fail();
}
@Test
public void demoSucceeds() {}
}
BTW:
@see