聚合彼此之间具有依赖关系的JUnit规则



在更复杂的单元测试中,我经常需要一组特定的规则。其中一些规则与另一个规则具有相关性。由于排序是相关的,因此我使用RuleChains。到目前为止一切都很好。

然而,这在大多数测试中都是重复的(偶尔会使用额外的规则)。这种重复不仅让人觉得没有必要和繁琐,而且在许多地方也需要进行调整,因为应该整合一项额外的规则。

我想要的是规则规则,即包含或聚合其他(应用程序和测试特定)规则的(预定义)规则。

我将举一个目前情况的例子:

public LoggingRule logRule = new LogRule();
public ConfigurationRule configurationRule = new ConfigurationRule();
public DatabaseConnectionRule dbRule = new DatabaseConnectionRule();
public ApplicationSpecificRule appRule = new ApplicationSpecificRule();
@Rule
RuleChain chain = RuleChain.outerRule(logRule)
                           .around(configurationRule)
                           .around(dbRule)
                           .around(appRule);

假设给定的规则相互依赖,例如ApplicationSpecificRule要求首先执行DatabaseConnectionRule以建立连接,ConfigurationRule已初始化空配置,等等。还假设对于这个(相当复杂的测试),实际上需要所有规则。

到目前为止,我能想到的唯一解决方案是创建返回预定义RuleChain的工厂方法:

public class ApplicationSpecificRule extends ExternalResource
{
    public static RuleChain basicSet()
    {
         return RuleChain.outerRule(new LogRule())
                         .around(new ConfigurationRule())
                         .around(new DatabaseConnectionRule())
                         .around(new ApplicationSpecificRule());
    }
}

在测试中,可以按如下方式使用:

@Rule
RuleChain chain = ApplicationSpecificRule.basicSet();

这样就消除了重复,可以很容易地整合额外的规则。甚至可以将特定于测试的规则添加到RuleChain中。然而,当需要额外设置时,无法访问包含的规则(假设您需要ApplicationSpecificRule来创建一些域对象等)

理想情况下,这将被扩展为还支持使用其他预定义的集合,例如建立在规则的basicSet之上的advandancedSet

这能以某种方式简化吗?这是一个好主意,还是我在某种程度上滥用了规则?重组测试会有帮助吗?想法?

TestRule接口只有一个方法,因此可以很容易地定义自己的自定义规则,该规则委托给RuleChain并保留对其他规则的引用:

public class BasicRuleChain implements TestRule {
  private final RuleChain delegate;
  private final DatabaseConnectionRule databaseConnectionRule
      = new DatabaseConnectionRule();
  public BasicRuleChain() {
    delegate = RuleChain.outerRule(new LogRule())
        .around(new ConfigurationRule())
        .around(databaseConnectionRule)
        .around(new ApplicationSpecificRule());
  }
  @Override
  public Statement apply(Statement base, Description description) {
    return delegate.apply(base, description
  }
  public Connection getConnection() {
    return databaseConnectionRule.getConnection();
  }
}

没有比这更简单的了,是吗?唯一能让它变得更简单的是只使用实例而不是工厂,因为你不需要一直使用新的实例。

最新更新