If the business rules state that [some Thing] should only be created if ten conditions are met, it seems crazy to write a test for each true/false permutation of those conditions. For example if I wanted to test that a Thing is not created when only 9/10 conditions are satisfied, I’d have to to set up the test data in such a way that the first eight conditions are satisfied.
public class ThingCreator {
// ...
public void create(SomeRequestToCreateThing request) {
final var condition1 = isCondition1Satisfied(request);
final var condition2 = isCondition2Satisfied(request);
// condition3, condition4 etc etc
if (condition1 && condition2) { // && condition3 && condition4 etc etc
doCreate(request);
}
}
}
(It’s probably not great to have logic for request validation and actual Thing-creation in the same method, but it makes the example code shorter.)
My first thought is that if I abstract out the conditions and inject them into the Creator, when I test the Creator I don’t technically have to test every combination; I only have to test that the Creator calls isSatisfied on some stubbed criteria:
public interface Criterion {
boolean isSatisfied(SomeRequestToCreateThing request);
}
public class ThingCreator {
// ...
private final List<Criterion> criteria;
public void create(SomeRequestToCreateThing request) {
final var allSatisfied = this.criteria.stream()
.allMatch(criterion -> criterion.isSatisfied(request));
if (allSatisfied) {
doCreate(request);
}
}
}
But then I realized that it might be “cheating” because I’m not really testing the actual business requirements (these exact N business conditions must be satisfied to create a Thing).
This seems like a really common problem, so I’m wondering if there’s a design pattern out there I should be applying, or maybe I just need to adjust my testing philosophy.