如何使用嵌套生成器编写jqwik生成器方法 [英] How to write a jqwik generator method with nested generators

查看:187
本文介绍了如何使用嵌套生成器编写jqwik生成器方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用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;
    });
}

您可以希望看到的是,创建生成器就像进行数据流编程一样:从某些基本仲裁-lowThresholdArbhighThresholdArb开始,您可以对它们进行组合,映射和过滤.最后,必须返回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生成器方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆