如何按特定顺序应用JUnit规则



我们通过测试规则强制每个测试超时:

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");
     // ...
 }

相关内容

  • 没有找到相关文章

最新更新