如何将JUnit @Rule应用于套件中的所有测试用例

jba*_*nom 9 java junit junit4

我正在使用JUnit 4.10来运行测试套件,并且我已经实现了一个"重试失败测试"规则,遵循Matthew Farwell在如何立即重新运行失败的JUnit测试中的精彩笔记帖子.我用以下代码创建了一个"RetryTestRule"类:

public class RetryTestRule implements TestRule {

  private final int retryCount;

  public RetryTestRule(int retryCount) {
    this.retryCount = retryCount;
  }

  @Override
  public Statement apply(Statement base, Description description) {
    return statement(base, description);
  }

  private Statement statement(final Statement base, final Description description) {
    return new Statement() {
      @Override
      public void evaluate() throws Throwable {
        Throwable caughtThrowable = null;

        // retry logic
        for (int i = 0; i < retryCount; i++) {
          try {
            base.evaluate();
            return;
          } catch (Throwable t) {
            caughtThrowable = t;
            System.err.println(description.getDisplayName() + ": run " + (i + 1) + "     failed");
          }
        }
        System.err.println(description.getDisplayName() + ": Giving up after " + retryCount
            + " failures");
        throw caughtThrowable;
      }
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

当在测试用例中将其作为规则使用时,它可以很好地工作,但在套件的每个测试用例中使用@Rule表示法而不是Suite定义中的单个表示法似乎不是最佳的,所以在检查了一下之后我尝试了我的Suite类中新的@ClassRule表示法:

@RunWith(Suite.class)
@SuiteClasses({
  UserRegistrationTest.class,
  WebLoginTest.class
})
public class UserSuite {    
  @ClassRule
  public static RetryTestRule retry = new RetryTestRule(2);
}
Run Code Online (Sandbox Code Playgroud)

问题是这没有按预期工作:失败的测试没有被重试.有没有人试过这个并知道解决方案?非常感谢帮助!

Mat*_*ell 9

@ClassRules每个类执行一次,而不是每个方法执行一次.要为每个方法执行一次某些操作,您需要@Rule像使用一样使用,或者按照如何在套件中定义JUnit方法规则的答案.

要重用现有规则,可以使用RunRules该类将规则添加到要运行的规则列表中,如下所示:

public class MyRunner extends BlockJUnit4ClassRunner {
    public MyRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }

    @Override
    protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
        Description description= describeChild(method);
        if (method.getAnnotation(Ignore.class) != null) {
            notifier.fireTestIgnored(description);
        } else {
            RunRules runRules = new RunRules(methodBlock(method), Arrays.asList(new TestRule[]{new RetryTestRule(3)}), description);
            runLeaf(runRules, description, notifier);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是使用上面答案的例子.您可以将两个答案组合在一起以获得更精细的控制,如果您的测试中有注释,则可以创建RetryTestRule.