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

Java 如何按特定顺序应用JUnit规则?,java,junit,timeout,Java,Junit,Timeout,我们通过测试规则对每个测试强制执行超时: public abstract class BaseTestCase { @Rule public final Timeout timeout = new Timeout(60*1000); } 那么我们的GUI测试显然必须在EDT上运行,因此他们也有一个测试规则: public class TestSomeController extends BaseTestCase { @Rule public final RunO

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

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() { /* ... */ }
}
这两条规则都涉及到干扰测试运行的线程<代码>超时创建一个新线程,然后在N毫秒后将其杀死
RunOnEventDispatchThread
在EDT上运行
Runnable
,然后等待任务完成

在JUnit4.10之前,它一直运行良好,但是我们刚刚升级到JUnit4.11,现在似乎测试规则的顺序已经改变了

当前JUnit似乎是按“逻辑”顺序应用规则,因此它应用
Timeout
,然后应用
runonevendispatchthread

这意味着
RunOnEventDispatchThread
结束于
语句的“外部”。因此它在EDT上运行任务,但该任务现在是“生成一个新线程来运行测试”——因为它生成了一个新线程,所以测试失败,因为Swing调用现在在错误的线程上被调用

显然,JUnit4.10是以另一种顺序运行测试规则的。有没有办法影响这一点


请注意,这类问题的现有答案都已通过使用
规则链
解决。据我所知,我们不能使用
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() { /* ... */ }

}

我不太熟悉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
从中,您可以执行以下操作:

    @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

这可能不是一个坏方法。至少直到我们想在中间插入一个规则为止。是的,你必须死一次。但问题是你的测试不应该那么复杂。一定有办法减轻他们的痛苦。你所描述的问题我从来没有涉及过。也许重新设计(测试)会有所帮助。这可能不是一个坏方法。至少直到我们想在中间插入一个规则为止。是的,你必须死一次。但问题是你的测试不应该那么复杂。一定有办法减轻他们的痛苦。你所描述的问题我从来没有涉及过。也许重新设计(测试)会有所帮助。