检测@After方法中朱尼特测试的失败或错误

2022-09-01 04:41:37

在 JUnit 中,有没有办法在@After注释的方法中检测测试用例中是否存在测试失败或错误?

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

boolean withoutFailure = false;

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

@After
public void tearDown() {
   if(!withoutFailuere) {
      this.dontReuseTestenvironmentForNextTest();
   }
}

这很丑陋,因为需要照顾测试代码中的“基础设施”(没有Failure标志)。

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


答案 1

如果你有幸使用JUnit 4.9或更高版本,TestWatcher将完全按照你的意愿去做。

分享和享受!


答案 2

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

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


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 {}

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;
    }
}

用法:

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() {}
}

顺便说一句:

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

@see


推荐