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
generateRule
method on the wrong assumption that an arbitrary'smap
method performed any real action when called. This is not the case. The fact thatmap
returns 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
generateRule
method 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 -
lowThresholdArb
andhighThresholdArb
- you combine, map and filter those. In the end a single instance ofArbitrary
must 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.