聚合具有彼此依赖关系的 JUnit 规则
Aggregating JUnit Rules with dependencies between one another
在更复杂的单元测试中,我经常要求存在一组特定的规则。其中一些规则与另一个规则有依赖关系。由于排序是相关的,因此我为此使用 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 已初始化空配置等。
还假设对于这个(相当复杂的测试)所有规则实际上都是必需的。
到目前为止我能想到的唯一解决方案是创建 return 预定义 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
来创建一些域对象等)。
理想情况下,这将扩展为也支持使用其他预定义集,例如advandancedSet
建立在 basicSet
规则之上。
这可以简化吗?首先这是一个好主意还是我以某种方式滥用规则?它有助于重组测试吗?
想法?
没有那么简单,不是吗?唯一能让它变得更简单的是只使用实例而不是工厂,因为您不需要一直使用新实例。
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();
}
}
在更复杂的单元测试中,我经常要求存在一组特定的规则。其中一些规则与另一个规则有依赖关系。由于排序是相关的,因此我为此使用 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 已初始化空配置等。 还假设对于这个(相当复杂的测试)所有规则实际上都是必需的。
到目前为止我能想到的唯一解决方案是创建 return 预定义 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
来创建一些域对象等)。
理想情况下,这将扩展为也支持使用其他预定义集,例如advandancedSet
建立在 basicSet
规则之上。
这可以简化吗?首先这是一个好主意还是我以某种方式滥用规则?它有助于重组测试吗? 想法?
没有那么简单,不是吗?唯一能让它变得更简单的是只使用实例而不是工厂,因为您不需要一直使用新实例。
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();
}
}