9

我正在尝试改进现有的自动化 Selenium 测试系统。我的目标是重复由于连接问题而失败的测试。我找到并尝试关注这个线程如何立即重新运行失败的 JUnit 测试?这表明自己非常有用。

在我的例子中,套件是由类组成的,所以我尝试用@ClassRule 替换@Rule,以便在每次尝试时重复@Before 和@After 部分。我很抱歉我的无知,但我应该把这条规则放在哪里?在我的套房课上?或者在代表测试的类中?

4

4 回答 4

5

我是如何立即重新运行失败的 JUnit 测试的原始回答者?

如果我理解正确,您遇到的问题是由于@Before在 中的代码之前执行RetryRule,而在@After之后执行。

因此,您当前的行为类似于:

@Before
@Retry
test code
@Retry
@After

但是你可以实现你的@Beforeand@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
    }
}

然后你不需要@Beforeand @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,则不再需要 and 上的注释@Rule,但您需要.ExternalResourceRetryRuleRuleChain

于 2015-01-21T09:45:01.490 回答
4

这是我基于问题中提到的解决方案。

它是 a @Rule, FailedRule和 a @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 
于 2015-01-19T17:15:33.447 回答
0

你用or属性装饰测试名称本身:@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是引发异常的 a 。

于 2013-05-24T16:25:31.250 回答
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将包含测试运行的最后结果,因此在分析失败的测试后,您可以再次运行它。

于 2015-01-19T15:05:04.037 回答