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

时间:2012-01-27 14:31:42

标签: java junit junit4

我正在使用JUnit 4.10来运行测试套件,并且我在How to Re-run failed JUnit tests immediately?帖子中的Matthew Farwell的精彩笔记之后实施了“重试失败测试”规则。我使用以下代码创建了一个“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;
      }
    };
  }
}

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

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

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

1 个答案:

答案 0 :(得分:9)

@ClassRule每个类执行一次,而不是每个方法执行一次。要为每种方法执行一次某项操作,您需要像使用@Rule一样使用RunRules,或者按照How to define JUnit method rule in a suite?的回答。

要重用现有规则,您可以使用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); } } } 类将规则添加到要运行的规则列表中,如下所示:

{{1}}

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