您应该注意的一件重要的事情是:“永远不要创建自己的样本。让 jqwik 决定何时这样做。” 换句话说:Arbitrary.sample()
仅用于测试生成器,例如在 JShell 中,或使用 jqwik 属性之外的生成器。
你需要的是Arbitrary.flatMap()
. 每当需要一个生成器的结果来馈送另一个生成器时,都需要平面映射。所以你的第一次尝试可能是:
@Provide
Arbitrary<Map<Integer, Integer[]>> llstPairs() {
Arbitrary<Integer[]> vals = sortedArrayGenerator().filter(array -> array.length > 0);
return vals.flatMap(array -> {
Arbitrary<Integer> keys = Arbitraries.of(array);
return Arbitraries.maps(keys, vals);
});
}
两个旁注:
但是,这并不容易,因为为地图生成的数组与用于键的数组不同。您必须确保在创建地图时使用完全相同的数组。所以你可以选择:
@Provide
Arbitrary<Map<Integer, Integer[]>> llstPairs() {
Arbitrary<Integer[]> vals = sortedArrayGenerator().filter(array -> array.length > 0);
return vals.flatMap(array -> {
Arbitrary<Integer> keys = Arbitraries.of(array);
Arbitrary<List<Integer>> listOfKeys = keys.list();
return listOfKeys.map(lok -> {
Map<Integer, Integer[]> map = new HashMap<>();
for (Integer k : lok) {
map.put(k, array);
}
return map;
});
});
}
考虑到这一点 - 据我所知 - 你并不真正需要地图,但想要一个键数组对列表,这是相当复杂的。这就是为什么我会这样做:
@Provide
Arbitrary<List<Tuple.Tuple2<Integer, Integer[]>>> listOfPairs() {
Arbitrary<Integer[]> vals = sortedArrayGenerator().filter(array -> array.length > 0);
return vals.flatMap(arrayOfInt -> {
Arbitrary<Integer> key = Arbitraries.of(arrayOfInt);
return key.map(k -> Tuple.of(k, arrayOfInt)).list();
});
}
这里有一个属性来检查它是否做了它应该做的事情:
@Property(tries = 100)
void listOfPairs_keyIsInArray(@ForAll("listOfPairs") List<Tuple.Tuple2<Integer, Integer[]>> listOfPairs) {
for (Tuple.Tuple2<Integer, Integer[]> pair : listOfPairs) {
Integer key = pair.get1();
Integer[] array = pair.get2();
Assertions.assertThat(array).contains(key);
}
}