Using jqwik.net, trying to generate a Rule class with a a nested RuleConfig class inside it. The RuleConfig class has a nested ruleProps which is a Map
The statusReturnedFromApplyingRule method always returns an initialized Rule instead of using the @provide method values ??
Returned Rule:
rule:Rule{ruleId='null', inputMetricSelector=null, ruleConfig='RuleConfig{ruleType='null', ruleProps={}}'}, elements:[{}]
Here is my code:
public class RangeMatchRuleTest {
@Property
@Report(Reporting.GENERATED)
boolean statusReturnedFromApplyingRule(@ForAll("generateRule") Rule rule,
@ForAll("generateInputMapElements") Iterable<Map<String, Object>> elements) {
RangeMatchRule rangeMatchRule = new RangeMatchRule();
final RuleIF.Status status = rangeMatchRule.applyRule(rule, elements);
return RuleIF.getEnums().contains(status.toString());
}
@Provide
Arbitrary<Rule> generateRule() {
Rule rule = new Rule();
RuleConfig ruleConfig = new RuleConfig();
Map<String, Object> ruleProps = new HashMap<>();
Arbitrary<Double> lowThresholdArb = Arbitraries.doubles()
.between(0.0, 29.0);
lowThresholdArb.allValues().ifPresent(doubleStream -> ruleProps.put(Utils.LOW_THRESHOLD, doubleStream.findFirst().get()));
//lowThresholdArb.map(lowThreshold -> ruleProps.put(Utils.LOW_THRESHOLD, lowThreshold) );
Arbitrary<Double> highThresholdArb = Arbitraries.doubles()
.between(30.0, 50.0);
highThresholdArb.map(highThreshold -> ruleProps.put(Utils.HIGH_THRESHOLD, highThreshold));
ruleConfig.setRuleProps(ruleProps);
rule.setRuleConfig(ruleConfig);
return Arbitraries.create(() -> rule);
}
@Provide
Arbitrary<Iterable<Map<String, Object>>> generateInputMapElements() {
Arbitrary<Double> metricValueArb = Arbitraries.doubles()
.between(0, 50.0);
Map<String, Object> inputMap = new HashMap<>();
metricValueArb.map(metricValue -> inputMap.put(Utils.METRIC_VALUE, metricValue));
List<Map<String, Object>> inputMapLst = new ArrayList<>();
inputMapLst.add(inputMap);
return Arbitraries.create(() -> inputMapLst);
}
}
TIA
You are building the
generateRulemethod on the wrong assumption that an arbitrary'smapmethod performed any real action when called. This is not the case. The fact thatmapreturns another arbitrary instance gives a strong hint.The underlying idea you have to grasp is that a provider method - the method annotated with
@Provide- is nothing but a "description" of the generation process; it will only be called once. The actual object generation happens afterwards and is controlled by the framework.Here's a reworked
generateRulemethod that should do what you intended:What you can hopefully see is that creating a generator is like dataflow programming: Starting from some base arbitraries -
lowThresholdArbandhighThresholdArb- you combine, map and filter those. In the end a single instance ofArbitrarymust be returned.BTW: If you want this generator to be applied each time when you need a
Rule, you could write the following class:and register it as a default provider.