2.0.0 |
|
---|
#10 在 #shrinking
78KB
2K SLoC
quickcheck
QuickCheck 是一种使用随机生成的输入进行属性测试的方法。这个包包含随机生成和缩小整数、浮点数、元组、布尔值、列表、字符串、选项和结果的能力。QuickCheck 所需的一切就是一个属性函数——它将随机生成该函数的输入,并为每一组输入调用属性。如果属性失败(无论是由于运行时错误,如索引越界,还是由于不满足您的属性),则输入将被“缩小”以找到更小的反例。
列表和数字的缩小策略使用二分搜索快速覆盖输入空间。
文档
API 完全文档化:https://docs.rs/quickcheck.
#[quickcheck]
属性
为了更容易编写 QuickCheck 测试,#[quickcheck]
属性会将属性函数转换为 #[test]
函数。
要使用 #[quickcheck]
属性,您必须从 quickcheck_macros
包导入 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 的关键部分,可以自动简化属性的 counter-examples。例如,如果您错误地将反转向量的函数定义为:(为这个虚构的例子道歉)
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 quickcheck::{Arbitrary, Gen};
impl Arbitrary for Point {
fn arbitrary(g: &mut Gen) -> Point {
Point {
x: i32::arbitrary(g),
y: i32::arbitrary(g),
}
}
}
许可协议
双许可协议,MIT或UNLICENSE。
依赖项
~295–520KB