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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6981903/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 18:08:11  来源:igfitidea点击:

Detect Failure or Error of Junit Test in @After method

javajunit

提问by Ralph

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?

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

One uglysolution would be something like that:

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

boolean withoutFailure = false;

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

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

This is ugly because one need to take care of the "infrastructure" (withoutFailure flag) in the test code.

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

I hope that there is something where I can get the test status in the @After method!?

我希望有什么可以在@After 方法中获得测试状态的地方!?

采纳答案by dsaff

If you are lucky enough to be using JUnit 4.9 or later, TestWatcherwill do exactly what you want.

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

Share and Enjoy!

分享和享受!

回答by Ralph

I extend dsaff's answer to solve the problem that a TestRulecan not execute some code snipped between the execution of the test-method and the after-method. So with a simple MethodRuleone can not use this rule to provide a success flag that is use in the @Afterannotated methods.

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

My idea is a hack! Anyway, it is to use a TestRule(extends TestWatcher). A TestRulewill get knowledge about failed or success of a test. My TestRulewill then scan the class for all Methods annotated with my new AfterHackannotations and invoke that methods with a success flag.

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



AfterHackannotation

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

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


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:

顺便提一句:

  • 1) Hopefully there is a better solution in Junit5
  • 2) The better way is to use the TestWatcher Rule instead of the @Before and @After Method at all (that is the way I read dsaff's answer)
  • 1) 希望 Junit5 有更好的解决方案
  • 2)更好的方法是使用 TestWatcher Rule 而不是 @Before 和 @After 方法(这是我阅读 dsaff 答案的方式)

@see

@看

回答by Tom Tresansky

I think what you'll want to do is add a RunListenerto the JUnit core. You can then override the testFailuremethod to set your withoutFailureflag in a single place so you can check it in your @Afterannotated method.

我认为您要做的是向 JUnit 核心添加一个RunListener。然后,您可以覆盖该testFailure方法以withoutFailure在单个位置设置您的标志,以便您可以在带@After注释的方法中检查它。

Also see: this blog postfor a discussion of some issues with this approach when using earlier versions of JUnit.

另请参阅:此博客文章讨论了使用早期版本的 JUnit 时这种方法的一些问题。

回答by Gustave

I don't know any easy or elegant way to detect the failure of a Junit test in an @After method.

我不知道在 @After 方法中检测 Junit 测试失败的任何简单或优雅的方法。

If it is possible to use a TestRule instead of an @After method, one possibility to do it is using two chained TestRules, using a TestWatcher as the inner rule.

如果可以使用 TestRule 而不是 @After 方法,一种可能性是使用两个链接的 TestRules,使用 TestWatcher 作为内部规则。

Example:

例子:

    package org.example;

    import static org.junit.Assert.fail;

    import org.junit.Rule;
    import org.junit.Test;
    import org.junit.rules.ExternalResource;
    import org.junit.rules.RuleChain;
    import org.junit.rules.TestRule;
    import org.junit.rules.TestWatcher;
    import org.junit.runner.Description;

    public class ExampleTest {

      private String name = "";
      private boolean failed;

      @Rule
      public TestRule afterWithFailedInformation = RuleChain
        .outerRule(new ExternalResource(){
          @Override
          protected void after() {
            System.out.println("Test "+name+" "+(failed?"failed":"finished")+".");
          }      
        })
        .around(new TestWatcher(){
          @Override
          protected void finished(Description description) {
            name = description.getDisplayName();
          }
          @Override
          protected void failed(Throwable e, Description description) {
            failed = true;
          }      
        })
      ;

      @Test
      public void testSomething(){
        fail();
      }

      @Test
      public void testSomethingElse(){
      }

    }