在@After方法中检测Junit测试的失败或错误

Ral*_*lph 29 java junit

JUnit中是否有一种方法可以在@After注释方法中检测测试用例中是否存在测试失败或错误?

一个丑陋的解决方案是这样的:

boolean withoutFailure = false;

@Test
void test() {
  ...
  asserts...
  withoutFailure = true;
}

@After
public void tearDown() {
   if(!withoutFailuere) {
      this.dontReuseTestenvironmentForNextTest();
   }
}
Run Code Online (Sandbox Code Playgroud)

这很难看,因为需要在测试代码中处理"基础设施"(withoutFailure标志).

我希望有一些东西可以在@After方法中获得测试状态!?

dsa*_*aff 10

如果您有幸使用JUnit 4.9或更高版本,TestWatcher将完全按照您的要求进行操作.

分享和享受!

  • 由于这篇文章TestWatchman现已弃用,因此TestWatcher是新类. (5认同)
  • 这不适用于JUnit 4.12和Arquillian 1.1.10,因为TestWatcher在执行`@ After`方法后得到失败的通知. (4认同)
  • 根据https://github.com/junit-team/junit4/issues/906这是预期的行为,所以我相信这个答案虽然有用但是被错误地接受了 - 它没有达到问题中所述的目标. (2认同)
  • 这个答案是错的,这浪费了我的时间. (2认同)

Ral*_*lph 5

我扩展了 dsaff 的答案,以解决TestRule无法执行在 test-method 和 after-method 执行之间截取的某些代码的问题。因此,MethodRule不能使用简单的规则来提供在带@After注释的方法中使用的成功标志。

我的想法是一个黑客!无论如何,它是使用TestRule(extends TestWatcher)。ATestRule将获得有关测试失败或成功的知识。TestRule然后我将扫描类中所有用我的新AfterHack注释注释的方法,并使用成功标志调用该方法。


AfterHack 注解

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 {}
Run Code Online (Sandbox Code Playgroud)

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<Method> getAfterHackMethods(Class<?> testClass) {
        List<Method> results = new ArrayList<>();            
        for (Method method : testClass.getMethods()) {
            if (method.isAnnotationPresent(AfterHack.class)) {
                results.add(method);
            }
        }
        return results;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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() {}
}
Run Code Online (Sandbox Code Playgroud)

顺便提一句:

  • 1)希望在 Junit5 中有更好的解决方案
  • 2)更好的方法是使用 TestWatcher Rule 而不是 @Before 和 @After 方法(这是我阅读 dsaff 答案的方式)

@看