我正在尝试改进现有的自动化Selenium测试系统。我的目标是重复由于连接问题而失败的测试。我已经找到并尝试遵循这个线程如何立即重新运行失败的JUnit测试?这显示了自己非常有用。
在我的例子中,套件是由类组成的,所以我试着用@类规则代替@规则,以便每次尝试都重复@之前和@之后部分。对不起,我的无知,但是我应该把这个规则放在哪里?在我的套件类中?还是在代表测试的类中?
我是如何立即重新运行失败的JUnit测试的原始回答者?
如果我理解正确,您遇到的问题是由于@之前
在RetryLaw
中的代码之前执行,而@之后
在之后执行。
所以你现在的行为是这样的:
@Before
@Retry
test code
@Retry
@After
但是您可以将您的@之前
和@之后
作为规则实现-有一个规则ExternalResource就是这样做的。您将实现@之前
和@之后
作为规则:
@Rule public ExternalResource beforeAfter = new ExternalResource() {
public void before() {
// code that was in @Before
}
public void after() {
// code that was in @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
,您不再需要ExternalResource
和RetryLaw
上的@Law
注释,而是在RuleChain
上。
这是我根据问题中提到的解决方案。
它是@Law
、FailedLaw和@ClassLaw
、RetryLaw的组合
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
您可以使用@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
。