如何将任意抗议值的转换排除在测试用例主体之外?

问题描述 投票:1回答:1

我想彻底测试两个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);
}

如何将任意值的转换排除在测试用例主体之外?我不了解关于策略的任何代码示例,并且Stack Overflow很少有与抗议相关的问题。

testing rust property-based-testing
1个回答
2
投票

BTreeSetStrategy中有一个内置的BTreeSetStrategy,因此相对简单:

proptest

某些语法不是香草Rust,所以可能需要进一步说明:

  • 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!语法以生成输入。
  • Proptest策略是内置的或用户定义的。定义策略的一种方法是在in Strategy宏内部。同样,这是一个普通的Rust函数,除了它可以有两个参数列表。第一个参数列表是通常的输入;第二个可以使用第一个的prop_compose!语法和参数。返回类型指示所生成的值的类型。在这种情况下,两个in Strategy的元组。
  • 您可能已经猜到了,Proptest板条箱附带了元组的BTreeSet实现,因此实现Strategy的类型的元组本身就是Strategy。这就是为什么函数Strategy可以用作一个的原因。
© www.soinside.com 2019 - 2024. All rights reserved.