问题描述
使用jqwik.net,尝试生成其中包含嵌套RuleConfig类的Rule类.RuleConfig类具有一个嵌套的ruleProps,它是一个Map
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
statusReturnedFromApplyingRule方法始终返回初始化的Rule,而不是使用@provide方法的值?返回的规则:rule:Rule{ruleId='null', inputMetricSelector=null, ruleConfig='RuleConfig{ruleType='null', ruleProps={}}'}, elements:[{}]
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:[{}]
这是我的代码:
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
推荐答案
您在错误的假设上构建generateRule
方法,即任意的map
方法在被调用时会执行任何实际操作.不是这种情况. map
返回另一个任意实例的事实提供了有力的暗示.
You are building the generateRule
method on the wrong assumption that an arbitrary's map
method performed any real action when called. This is not the case. The fact that map
returns another arbitrary instance gives a strong hint.
您必须掌握的基本思想是提供者方法-用@Provide
注释的方法-仅仅是生成过程的描述";它只会被调用一次.实际的对象生成是在此之后发生的,并由框架控制.
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.
这是一个经过重新设计的generateRule
方法,应该可以实现您的预期目的:
Here's a reworked generateRule
method that should do what you intended:
@Provide
Arbitrary<Rule> generateRule() {
Arbitrary<Double> lowThresholdArb = Arbitraries.doubles()
.between(0.0, 29.0);
Arbitrary<Double> highThresholdArb = Arbitraries.doubles()
.between(30.0, 50.0);
Arbitrary<RuleConfig> configArb =
Combinators.combine(lowThresholdArb, highThresholdArb)
.as((low, high) -> {
Map<String, Object> ruleProps = new HashMap<>();
ruleProps.put(Utils.LOW_THRESHOLD, low);
ruleProps.put(Utils.HIGH_THRESHOLD, high);
RuleConfig ruleConfig = new RuleConfig();
ruleConfig.setRuleProps(ruleProps);
return ruleConfig;
});
return configArb.map(config -> {
Rule rule = new Rule();
rule.setRuleConfig(config);
return rule;
});
}
您可以希望看到的是,创建生成器就像进行数据流编程一样:从某些基本仲裁-lowThresholdArb
和highThresholdArb
开始,您可以对它们进行组合,映射和过滤.最后,必须返回Arbitrary
的单个实例.
What you can hopefully see is that creating a generator is like dataflow programming: Starting from some base arbitraries - lowThresholdArb
and highThresholdArb
- you combine, map and filter those. In the end a single instance of Arbitrary
must be returned.
BTW:如果希望每次需要Rule
时都应用此生成器,则可以编写以下类:
BTW: If you want this generator to be applied each time when you need a Rule
, you could write the following class:
public class RuleArbitraryProvider implements ArbitraryProvider {
@Override
public boolean canProvideFor(TypeUsage targetType) {
return targetType.isOfType(Rule.class);
}
@Override
public Set<Arbitrary<?>> provideFor(TypeUsage targetType, SubtypeProvider subtypeProvider) {
return Collections.singleton(generateRule());
}
private Arbitrary<Rule> generateRule() {
// Put here the code from above
...
}
}
这篇关于如何使用嵌套生成器编写jqwik生成器方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!