我想彻底测试两个BTreeSet
的交集的实现。我可以写:
use self::proptest::prelude::*;
proptest! {
#[test]
fn intersect_this(s1: BTreeSet<i32>, s2: BTreeSet<i32>) {
...
}
}
但是这具有较差的代码覆盖率,因为代码是专用的,在某些情况下随机集不太可能命中。一种特殊情况是元素范围几乎不相交的集合(一组的值<= x,另一组的值> = x)。在带有假设的Python中(我是个新手),我会写:
from hypothesis import given
from hypothesis.strategies import builds, integers, sets
from typing import Set
def touching_ranges(elements: Set[int], split: int):
return {elt for elt in elements if elt < split}.union({split}), \
{elt for elt in elements if elt > split}.union({split})
@given(builds(touching_ranges, sets(integers()), integers()))
def test_touching_ranges(sets):
s1, s2 = sets
assert len(s1.intersection(s2)) == 1
在Rust中,我只不过将所有东西塞进了体内:
#[test]
fn touching(mut s1: BTreeSet<i32>, split: i32) {
let mut s2 = s1.split_off(&split);
s1.insert(split);
s2.insert(split);
prop_assert_eq!(s1.intersection(&s2).count(), 1);
}
如何将任意值的转换排除在测试用例主体之外?我不明白我发现的有关策略的任何代码示例,因此通过抗议几乎无法实现(与快速检查相比)。
BTreeSetStrategy
中有内置的BTreeSetStrategy
。因此相对简单:
proptest
这里的某些语法不是use proptest::prelude::*;
use std::collections::BTreeSet;
prop_compose! {
fn touching_ranges()
(split : i32,
mut s1 : BTreeSet<i32>)
-> (BTreeSet<i32>, BTreeSet<i32>)
{
let mut s2 = s1.split_off(&split);
s1.insert(split);
s2.insert(split);
(s1, s2)
}
}
proptest! {
#[test]
fn touching((s1, s2) in touching_ranges()) {
assert_eq!(s1.intersection(&s2).count(), 1);
}
}
,因此可能需要进一步说明:
rust
宏内部,测试只是正常的proptest!
函数,除了它们也可以访问rust
语法以生成输入。in Strategy
策略是内置的或用户定义的。定义策略的一种方法是在proptest
宏内部。同样,只是普通的prop_compose!
函数,除了可以具有两个参数列表之外。第一个参数列表是通常的输入;但是,第二个可以使用第一个中的rust
语法和参数。返回类型指示所生成的值的类型。在这种情况下,两个in Strategy
的元组。