如何使用嵌套生成器编写 jqwik 生成器方法
How to write a jqwik generator method with nested generators
使用 jqwik.net,尝试生成规则 class,其中包含嵌套的 RuleConfig class。
RuleConfig class 有一个嵌套的 ruleProps,它是一个 Map
statusReturnedFromApplyingRule 方法总是returns 一个初始化规则而不是使用@provide 方法值??
返回规则:
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
returns 另一个任意实例给出了强烈的暗示。
你必须掌握的基本思想是提供者方法——用@Provide
注释的方法——不过是生成过程的"description";它只会被调用一次。实际的对象生成随后发生并由框架控制。
这是一个重新设计的 generateRule
方法,应该可以达到您的预期:
@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
的单个实例。
顺便说一句:如果您希望每次需要 Rule
时都应用此生成器,您可以编写以下内容 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
...
}
}
基于提供的答案的上述地图的其他示例:
@Provide
Arbitrary<Iterable<Map<String, Object>>> generateInputMapElements() {
Arbitrary<Double> metricValueArb = Arbitraries.doubles()
.between(0, 50.0);
Arbitrary<Map<String, Object>> inputMapArb =
metricValueArb.map(metricsValue -> {
Map<String, Object> inputMap = new HashMap<>();
inputMap.put(Utils.METRIC_VALUE, metricsValue);
return inputMap;
});
return inputMapArb.map(inputMap -> {
List<Map<String, Object>> inputMapLst = new ArrayList<>();
inputMapLst.add(inputMap);
return inputMapLst;
});
}
使用 jqwik.net,尝试生成规则 class,其中包含嵌套的 RuleConfig class。 RuleConfig class 有一个嵌套的 ruleProps,它是一个 Map
statusReturnedFromApplyingRule 方法总是returns 一个初始化规则而不是使用@provide 方法值??
返回规则:
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
returns 另一个任意实例给出了强烈的暗示。
你必须掌握的基本思想是提供者方法——用@Provide
注释的方法——不过是生成过程的"description";它只会被调用一次。实际的对象生成随后发生并由框架控制。
这是一个重新设计的 generateRule
方法,应该可以达到您的预期:
@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
的单个实例。
顺便说一句:如果您希望每次需要 Rule
时都应用此生成器,您可以编写以下内容 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
...
}
}
基于提供的答案的上述地图的其他示例:
@Provide
Arbitrary<Iterable<Map<String, Object>>> generateInputMapElements() {
Arbitrary<Double> metricValueArb = Arbitraries.doubles()
.between(0, 50.0);
Arbitrary<Map<String, Object>> inputMapArb =
metricValueArb.map(metricsValue -> {
Map<String, Object> inputMap = new HashMap<>();
inputMap.put(Utils.METRIC_VALUE, metricsValue);
return inputMap;
});
return inputMapArb.map(inputMap -> {
List<Map<String, Object>> inputMapLst = new ArrayList<>();
inputMapLst.add(inputMap);
return inputMapLst;
});
}