In more complex unit tests, I often require a certain set of Rules to be present. Some of these Rules have dependencies to another. As the ordering is relevant, I use RuleChains for that. All good so far.
This however is duplicated in most tests (with the occasional additional rule being used). Not only does this duplication feel unnecessary and cumbersome to repeat, it also needs to be adjusted in many places, when an additional Rule should be integrated.
What I would like to have is a Rule of Rules, i.e. a (predefined) Rule that contains or aggregates other (application & test specific) Rules.
I'll give an example of how this currently looks like:
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);
Assume that the given Rules depend on each other, e.g. the ApplicationSpecificRule requires that the DatabaseConnectionRule is executed first in order to establish a connection, the ConfigurationRule has initialized an empty configuration, etc. Also assume that for this (rather complex test) all rules are actually required.
The only solution I could come up with so far is to create factory methods that return a predefined RuleChain:
public class ApplicationSpecificRule extends ExternalResource
{
public static RuleChain basicSet()
{
return RuleChain.outerRule(new LogRule())
.around(new ConfigurationRule())
.around(new DatabaseConnectionRule())
.around(new ApplicationSpecificRule());
}
}
In a test this can then be used as follows:
@Rule
RuleChain chain = ApplicationSpecificRule.basicSet();
With that the duplication is removed and additional Rules can easily be integrated. One could even add test-specific Rules to that RuleChain. However one can't access the contained Rules when they are required for additional setup (assume you need the ApplicationSpecificRule
in order to create some domain object, etc.).
Ideally this would be extended to also support using other predefined sets, e.g. an advandancedSet
that builds on top of the basicSet
of Rules.
Can this be somehow simplified? Is it a good idea in the first place or am I somehow misusing Rules? Would it help to restructure the tests? Thoughts?
RuleChain
provide certain methods from the internally usedRules
though, but make theRules
themselves accessible. This way I'll not have to extend theBasicRuleChain
for every additional use case. – Boxing