使用Junit重新运行失败的测试

时间:2013-05-24 15:53:34

标签: java testing junit

我正在努力改进现有的自动化Selenium测试系统。 我的目标是重复因连接问题而失败的测试。 我发现并试图遵循这个显示自己非常有用的线程How to Re-run failed JUnit tests immediately?

在我的情况下,套件由类组成,所以我试图用@ClassRule替换@Rule,以便重复每次尝试@Before和@After部分。 对不起我很抱歉,但我应该把这条规则放在哪里?在我的套件课程中?或者在代表测试的类中?

4 个答案:

答案 0 :(得分:4)

以下是基于问题中提到的解决方案。

它是@Rule FailedRule @ClassRule RetryRule

的组合
public class RetryTest
{
    public static class FailedRule implements TestRule
    {       
        @Override
        public Statement apply(final Statement base, final Description description)
        {
             return new Statement()
             {
                    @Override
                    public void evaluate() throws Throwable
                    {
                        try
                        {
                            base.evaluate();
                        }
                        catch (Throwable t)
                        {
                            System.out.println(description.getDisplayName() + " failed");
                            retry.setNotGood();
                            if (retry.isLastTry())
                            {
                                System.out.println("No more retry !");
                                throw t;
                            }
                            else
                            {
                                System.out.println("Retrying.");
                            }
                        }
                    }
            };
        }
    }

    public static class RetryRule implements TestRule
    {
        private int retryCount, currentTry;

        private boolean allGood = false;

        public RetryRule(int retryCount)
        {
            this.retryCount = retryCount;
            this.currentTry = 1;
        }

        public boolean isLastTry()
        {
            return currentTry == retryCount;
        }

        public void setNotGood()
        {
            allGood = false;
        }

        public Statement apply(final Statement base, final Description description)
        {
            return new Statement()
            {
                @Override
                public void evaluate() throws Throwable
                {
                    // implement retry logic here
                    for (; currentTry <= retryCount && !allGood; currentTry++)
                    {
                        allGood = true;
                        System.out.println("Try #" + currentTry);
                        base.evaluate();
                    }
                }
            };
        }
    }

    @ClassRule
    public static RetryRule retry = new RetryRule(3);

    @Rule
    public FailedRule onFailed = new FailedRule();

    @BeforeClass
    public static void before()
    {
        System.out.println("Before...");
    }

    @AfterClass
    public static void after()
    {
        System.out.println("...After\n");
    }

    @Test
    public void test1()
    {
        System.out.println("> test1 running");
    }

    @Test
    public void test2()
    {
        System.out.println("> test2 running");
        Object o = null;
        o.equals("foo");
    }
}

它给出了:

Try #1
Before...
> test1 running
> test2 running
test2(RetryTest) failed
Retrying.
...After

Try #2
Before...
> test1 running
> test2 running
test2(RetryTest) failed
Retrying.
...After

Try #3
Before...
> test1 running
> test2 running
test2(RetryTest) failed
No more retry !
...After

如果我在o.equals("foo");中评论test2,那么在第一次尝试中一切正常:

Try #1
Before...
> test1 running
> test2 running
...After 

答案 1 :(得分:4)

我是How to Re-run failed JUnit tests immediately?

的原始回答者

如果我理解正确,您遇到的问题是@Before之前执行RetryRule,之后执行的@After

所以你现在的行为是这样的:

@Before
@Retry
test code
@Retry
@After

但您可以实施@Before@After作为规则 - 有一条规则ExternalResource就是这样做的。您将实施@Before@After作为规则:

@Rule public ExternalResource beforeAfter = new ExternalResource() {
    public void before() {
        // code that was in @Before
    }

    public void after() {
        // code that was in @After
    }
}

然后您不需要@Before@After。然后,您可以使用RuleChain链接这些规则。这会强制执行您的规则:

@Rule public RuleChain chain= RuleChain
                       .outerRule(new LoggingRule("outer rule")
                       .around(new LoggingRule("middle rule")
                       .around(new LoggingRule("inner rule");

因此,您的最终解决方案将是:

private ExternalResource beforeAfter = ...
private RetryRule retry = ...

@Rule public RuleChain chain = RuleChain
                               .outerRule(retry)
                               .around(beforeAfter);

请注意,如果您使用的是RuleChain,则不再需要@RuleExternalResource上的RetryRule注释,而是RuleChain

答案 2 :(得分:0)

您使用@After@Afterclass属性装饰测试名称

@After
@Test
@Category(SmokeTests.class)
public void testProductPageOnly() throws TimeoutException {
   //Some tests here.
}

@Afterclass
public static void SomeTest {
   //Some test here.
}

需要注意的是,@Afterclass始终运行;即使您使用引发异常的@Beforeclass

答案 3 :(得分:0)

这可以解决问题:

1)测试类应继承自junit.framework.TestCase

2)使用类似的东西运行测试

YourTestClass testClass = new YourTestClass();
TestResult result = testClass.run();
Enumeration<TestFailure> failures = result.failures();
if (result.failureCount() != 0)
{
   TestFailure fail = failes.nextElement();
   junit.framework.Test test = fail.failedTest();
   test.run( result );
}

最后result将包含测试运行的最后结果,因此在分析了哪些测试失败后,您可以再次运行它。