如何立即重新运行失败的 JUnit 测试?

新手上路,请多包涵

有没有一种方法可以让 JUnit 规则或类似的东西给每个失败的测试第二次机会,只需再次尝试运行它。

背景:我有一大组用 JUnit 编写的 Selenium2-WebDriver 测试。由于时间安排非常激进(点击后只有很短的等待时间),一些测试(100 次中有 1 次,并且总是不同的)可能会失败,因为服务器有时响应速度会慢一些。但我不能让等待时间太长以至于它肯定足够长,因为那样测试将永远持续下去。) - 所以我认为对于这个用例来说,测试是绿色的,即使它需要一秒钟也是可以接受的尝试。

当然最好是三分之二的多数(重复失败的测试 3 次,如果其中两次测试正确,则认为它们正确),但这将是未来的改进。

原文由 Ralph 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 706
2 个回答

您可以使用 TestRule 执行此操作。这将为您提供所需的灵活性。 TestRule 允许您围绕测试插入逻辑,因此您可以实现重试循环:

 public class RetryTest {
    public class Retry implements TestRule {
        private int retryCount;

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

        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;

                    // implement retry logic here
                    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
    public Retry retry = new Retry(3);

    @Test
    public void test1() {
    }

    @Test
    public void test2() {
        Object o = null;
        o.equals("foo");
    }
}

TestRule 的核心是 base.evaluate() ,它调用你的测试方法。所以围绕这个调用你放了一个重试循环。如果在您的测试方法中抛出异常(断言失败实际上是 AssertionError ),则测试失败,您将重试。

还有一件事可能有用。您可能只想将此重试逻辑应用于一组测试,在这种情况下,您可以将方法的特定注释添加到测试上方的 Retry 类中。 Description 包含该方法的注释列表。有关这方面的更多信息,请参阅我对 如何在每个 JUnit @Test 方法之前单独运行一些代码,而不使用 @RunWith 或 AOP? .

使用自定义 TestRunner

这是CKuck的建议,你可以自己定义Runner。您需要扩展 BlockJUnit4ClassRunner 并覆盖 runChild()。有关详细信息,请参阅我对 如何在套件中定义 JUnit 方法规则? . This answer详细说明了如何定义如何为套件中的每个方法运行代码,您必须为此定义自己的运行程序。

原文由 Matthew Farwell 发布,翻译遵循 CC BY-SA 3.0 许可协议

现在有一个更好的选择。如果您使用 Maven 插件,例如:surfire 或 failsefe,可以选择添加参数 rerunFailingTestsCount SurFire Api 。这些东西是在以下票证中实现的: Jira Ticket 。在这种情况下,您不需要编写自定义代码和插件自动修改测试结果报告。

我只看到这种方法的一个缺点:如果某些测试在课前/课后阶段失败,则不会重新运行测试。

原文由 user1459144 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题