#属性测试 #属性 #quickcheck #缩减 #模糊测试

qcheck

具有缩减功能的自动属性测试

1 个稳定版本

1.0.0 2022年12月4日

#576测试

Download history 100/week @ 2024-03-13 96/week @ 2024-03-20 96/week @ 2024-03-27 105/week @ 2024-04-03 92/week @ 2024-04-10 84/week @ 2024-04-17 74/week @ 2024-04-24 104/week @ 2024-05-01 57/week @ 2024-05-08 65/week @ 2024-05-15 70/week @ 2024-05-22 74/week @ 2024-05-29 183/week @ 2024-06-05 116/week @ 2024-06-12 157/week @ 2024-06-19 114/week @ 2024-06-26

590 每月下载量
11 个crate中使用 (直接使用4个)

Unlicense OR MIT

78KB
2K SLoC

quickcheck

QuickCheck是一种使用随机生成输入进行属性测试的方法。此crate包含了随机生成和缩减整数、浮点数、元组、布尔值、列表、字符串、选项和结果的能力。QuickCheck所需的所有东西就是一个属性函数——它将随机生成该函数的输入,并对每一组输入调用属性。如果属性失败(无论是由于运行时错误如索引越界,还是不满足您的属性),则输入将被“缩减”以找到更小的反例。

列表和数字的缩减策略使用二分搜索快速覆盖输入空间。

文档

API已完全文档化:https://docs.rs/qcheck.

#[quickcheck]属性

为了更方便地编写QuickCheck测试,#[quickcheck]属性将属性函数转换为#[test]函数。

要使用#[quickcheck]属性,您必须从quickcheck_macroscrate导入quickcheck宏。

#[cfg(test)]
mod tests {
    fn reverse<T: Clone>(xs: &[T]) -> Vec<T> {
        let mut rev = vec!();
        for x in xs {
            rev.insert(0, x.clone())
        }
        rev
    }

    #[quickcheck]
    fn double_reversal_is_identity(xs: Vec<isize>) -> bool {
        xs == reverse(&reverse(&xs))
    }
}

缩减

缩减是QuickCheck的一个关键部分,可以自动简化您属性的逆例。例如,如果您错误地定义了一个用于反转向量的函数:(对于这个虚构的例子,我表示歉意)

fn reverse<T: Clone>(xs: &[T]) -> Vec<T> {
    let mut rev = vec![];
    for i in 1..xs.len() {
        rev.insert(0, xs[i].clone())
    }
    rev
}

并且有一个属性来测试xs == reverse(reverse(xs))

fn prop(xs: Vec<isize>) -> bool {
    xs == reverse(&reverse(&xs))
}
quickcheck(prop as fn(Vec<isize>) -> bool);

那么在没有缩减的情况下,您可能得到一个反例,如下所示

[quickcheck] TEST FAILED. Arguments: ([-17, 13, -12, 17, -8, -10, 15, -19,
-19, -9, 11, -5, 1, 19, -16, 6])

这看起来相当神秘。但是启用缩减后,您几乎可以保证每次都会得到这个反例。

[quickcheck] TEST FAILED. Arguments: ([0])

这将使得调试变得更加容易。

增加测试数量

另一种方法是让quickcheck运行更多的属性。你可以通过tests()方法,或者通过环境变量QUICKCHECK_TESTS来实现。这将导致quickcheck运行更长的时间。与循环方法不同,这将花费有限的时间,这使得它更适合像发布周期这样的需求,真正对软件进行压力测试。

生成结构体

在QuickCheck中生成结构体非常简单。考虑以下示例,其中结构体Point被定义

struct Point {
    x: i32,
    y: i32,
}

为了生成一个随机的Point实例,你需要为结构体Point实现Arbitrary特质

use qcheck::{Arbitrary, Gen};

impl Arbitrary for Point {
    fn arbitrary(g: &mut Gen) -> Point {
        Point {
            x: i32::arbitrary(g),
            y: i32::arbitrary(g),
        }
    }
}

许可证

双许可,MIT或UNLICENSE

依赖项

300–520KB