1

我正在尝试 jqwik(版本 1.5.1),我从文档中读到我可以创建一个Arbitrary其生成的值取决于另一个提供的值Arbitrary,特别是使用该flatMap函数。

我的实际目标不同,但基于这个想法:我需要 2 Arbitrarys,它总是为单个测试生成不同的值。这是我尝试过的:

@Provide
private Arbitrary<Tuple.Tuple2<Integer, Integer>> getValues() {
  var firstArbitrary = Arbitraries.integers().between(1, Integer.MAX_VALUE);
  var secondArbitrary = firstArbitrary.flatMap(first ->
          Arbitraries.integers().between(1, Integer.MAX_VALUE).filter(i -> !i.equals(first)));

  return Combinators.combine(firstArbitrary, secondArbitrary).as(Tuple::of);
}

@Property
public void test(@ForAll("getValues") Tuple.Tuple2<Integer, Integer> values) {
  assertThat(values.get1()).isNotEqualTo(values.get2());
}

它立即因这个示例而失败:

Shrunk Sample (1 steps)
-----------------------
  arg0: (1, 1)

当然抛出AssertionError

java.lang.AssertionError: 
Expecting:
  1
not to be equal to:
  1

我希望该filter函数足以排除由生成的值,firstArbitrary但似乎甚至没有考虑它,或者更有可能它做了其他事情。我错过了什么?有没有更简单的方法来确保给定一定数量的integer生成器,它们总是产生不同的值?

4

1 回答 1

1

一个生成值影响下一代步骤的总体思路flatMap是正确的。您缺少的是通过在平面映射范围之外firstArbitrary组合和松散这种耦合。修复是次要的:secondArbitrary

@Provide
private Arbitrary<Tuple.Tuple2<Integer, Integer>> getValues() {
    var firstArbitrary = Arbitraries.integers().between(1, Integer.MAX_VALUE);
    return firstArbitrary.flatMap(
        first -> Arbitraries.integers().between(1, Integer.MAX_VALUE)
                            .filter(i -> !i.equals(first))
        .map(second -> Tuple.of(first, second))
    );
}

也就是说,还有更多——我认为更简单——实现目标的方法:

@Provide
private Arbitrary<Tuple.Tuple2<Integer, Integer>> getValues() {
    var firstArbitrary = Arbitraries.integers().between(1, Integer.MAX_VALUE);
    return firstArbitrary.tuple2().filter(t -> !t.get1().equals(t.get2()));
}

这摆脱了平面映射,这意味着在缩小 jqwik 的同时减少工作量。

另一种可能的解决方案:

@Provide
private Arbitrary<Tuple.Tuple2<Integer, Integer>> getValues() {
    var firstArbitrary = Arbitraries.integers().between(1, Integer.MAX_VALUE);
    return firstArbitrary.list().ofSize(2).uniqueElements().map(l -> Tuple.of(l.get(0), l.get(1)));
}

这个可能看起来有点复杂,但它的优点是没有使用平面映射和过滤。过滤通常会降低生成、边缘情况、穷举生成和收缩的性能。这就是为什么我尽可能不费力地避开过滤。

于 2021-04-06T07:00:04.007 回答