我们通过测试规则强制每个测试超时:
public abstract class BaseTestCase {
@Rule
public final Timeout timeout = new Timeout(60*1000);
}
那么我们的GUI测试显然必须在EDT上运行,所以他们也有一个测试规则:
public class TestSomeController extends BaseTestCase {
@Rule
public final RunOnEventDispatchThread runOnEventDispatchThread =
new RunOnEventDispatchThread();
@Test
public void testStuff() { /* ... */ }
}
这两个规则都涉及到干扰测试运行的线程。Timeout
创建一个新线程,然后在N毫秒后杀死它。RunOnEventDispatchThread
在EDT上运行Runnable
,然后等待任务完成。
在JUnit 4.10之前,这一直工作得很好,但我们刚刚升级到JUnit 4.11,现在似乎测试规则的顺序发生了变化。
当前JUnit似乎以"逻辑"顺序应用规则,因此它先应用Timeout
,然后应用RunOnEventDispatchThread
。
这意味着RunOnEventDispatchThread
最终在Statement
"洋葱"的"外面"。因此,它在EDT上运行任务,但该任务现在是"生成一个新线程来运行测试"—因为它生成了一个新线程,所以测试失败,因为Swing调用现在在错误的线程上被调用。
显然JUnit 4.10以另一种顺序运行测试规则。有办法影响这一点吗?
注意,这类问题的现有答案都是通过使用RuleChain
来解决的。据我所知,我们不能使用RuleChain
,因为那个类要求两个规则都在同一个类中,而我们的规则不是。
我不太熟悉JUnit中的规则排序,特别是RuleChain
类。我快速浏览了一下这个类的文档。当在模板方法中使用时,示例代码片段似乎是您的解决方案。
我可以想象下面的机制会起作用:
public abstract class BaseTestCase {
@Rule
public final RuleChain ruleChain = createRuleChain();
private RuleChain createRuleChain() {
return appendInnerRules(RuleChain.outerRule(createOuterRule()));
}
protected TestRule createOuterRule() {
return new Timeout(60 * 1000);
}
protected RuleChain appendInnerRules(RuleChain ruleChain) {
return ruleChain; // default behavior
}
}
public final class TestSomeController extends BaseTestCase {
protected RuleChain appendInnerRules(RuleChain ruleChain) {
return ruleChain.around(new RunOnEventDispatchThread());
}
@Test
public void testStuff() { /* ... */ }
}
在官方文档中,您可以这样做:
@Rule
public RuleChain chain= RuleChain
.outerRule(new LoggingRule("outer rule")
.around(new LoggingRule("middle rule")
.around(new LoggingRule("inner rule");
日志:
starting outer rule
starting middle rule
starting inner rule
finished inner rule
finished middle rule
finished outer rule
自junit 4.13
起,您可以使用元素顺序。
public class ThreeRules {
@Rule(order = 0)
public LoggingRule outer = new LoggingRule("outer rule");
@Rule(order = 1)
public LoggingRule middle = new LoggingRule("middle rule");
@Rule(order = 2)
public LoggingRule inner = new LoggingRule("inner rule");
// ...
}