Rust参数化测试库parameterized的使用,简化多参数测试用例管理与执行的Rust插件库
Rust参数化测试库parameterized的使用
parameterized是一个基于procedural macro的参数化测试库,当您需要用一个测试函数运行多种不同的输入组合时非常有用。
基本用法
在定义参数化测试用例时,应使用#[parameterized(...)]
属性代替#[test]
。这个库的灵感来自JUnit的@ParameterizedTest
。
示例代码
// 定义水果枚举
enum Fruit {
Apple,
Bramble(BrambleFruit),
Pear,
}
// 定义获取名称的trait
trait NameOf {
fn name_of(&self) -> &str;
}
// 为Fruit实现NameOf
impl NameOf for Fruit {
fn name_of(&self) -> &str {
match self {
Fruit::Apple => "apple",
Fruit::Bramble(fruit) => fruit.name_of(),
Fruit::Pear => "pear",
}
}
}
// 定义莓果枚举
enum BrambleFruit {
Blackberry,
}
// 为BrambleFruit实现NameOf
impl NameOf for BrambleFruit {
fn name_of(&self) -> &str {
match self {
BrambleFruit::Blackberry => "blackberry",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use parameterized::parameterized;
// 参数化测试示例
#[parameterized(fruit = {
Fruit::Apple,
Fruit::Pear,
Fruit::Bramble(BrambleFruit::Blackberry)
}, name = {
"apple", "pear", "blackberry"
})]
fn a_fruity_test(fruit: Fruit, name: &str) {
assert_eq!(fruit.name_of(), name)
}
}
自定义测试属性
默认情况下,parameterized
属性会生成带有#[test]
属性的测试用例。但有时需要使用不同的测试宏,比如#[tokio::test]
。
使用自定义测试宏
use parameterized::parameterized;
// 异步参数化测试示例
#[parameterized(input = {
0, 1
}, expected = {
5, 6
})]
#[parameterized_macro(tokio::test)] // 使用tokio测试宏
async fn add5(input: u32, expected: u32) {
assert_eq!(input + 5, expected);
}
注意事项:
#[parameterized_macro(...)]
必须始终在#[parameterized(...)]
属性之后指定- 目前只支持每个参数化测试函数一个
#[parameterized_macro(...)]
属性
IDE运行测试问题
由于IntelliJ IDEA目前不扩展属性宏,因此不会识别由parameterized
宏生成的测试用例。可以使用以下解决方法:
#[cfg(test)]
mod tests {
use super::*;
use parameterized::parameterized as pm; // 使用别名
use parameterized::ide; // 导入ide模块
mod squared_tests {
use super::*;
ide!(); // 使用ide宏
// 参数化测试
#[pm(input = {
-2, -1, 0, 1, 2
}, expected = {
4, 1, 0, 1, 4
})]
fn test_squared(input: i8, output: i8) {
assert_eq(squared(input), output);
}
}
}
完整示例
下面是一个完整的参数化测试示例,展示了如何测试一个简单的平方函数:
use parameterized::parameterized;
// 平方函数
fn squared(input: i32) -> i32 {
input * input
}
#[cfg(test)]
mod tests {
use super::*;
// 普通参数化测试
#[parameterized(input = {
-2, -1, 0, 1, 2
}, expected = {
4, 1, 0, 1, 4
})]
fn test_squared(input: i32, expected: i32) {
assert_eq!(squared(input), expected);
}
// 异步参数化测试示例
#[parameterized(input = {
1, 2, 3
}, expected = {
1, 4, 9
})]
#[parameterized_macro(tokio::test)] // 使用tokio测试宏
async fn test_squared_async(input: i32, expected: i32) {
assert_eq!(squared(input), expected);
}
}
导入方式
如果您不想在每个测试模块中都导入这个库,可以在您的crate根目录顶部添加以下代码:
#[cfg(test)]
#[macro_use] // 全局导入宏
extern crate parameterized;
许可证
parameterized采用双许可证:Apache License 2.0或MIT license。
Rust参数化测试库parameterized使用指南
parameterized
是一个简化Rust中多参数测试用例管理与执行的库,它允许你使用简洁的语法为同一个测试函数提供多组输入参数。
安装
在Cargo.toml
中添加依赖:
[dev-dependencies]
parameterized = "0.5.1"
基本用法
1. 简单参数化测试
use parameterized::parameterized;
#[parameterized(input = {1, 2, 3}, expected = {2, 3, 4})]
fn test_add_one(input: i32, expected: i32) {
assert_eq!(input + 1, expected);
}
2. 使用元组作为参数
#[parameterized(
input = {
(1, 2),
(3, 4),
(5, 6)
},
expected = {3, 7, 11}
)]
fn test_add(input: (i32, i32), expected: i32) {
assert_eq!(input.0 + input.1, expected);
}
3. 使用自定义类型
struct Point {
x: i32,
y: i32,
}
#[parameterized(
input = {
Point { x: 1, y: 2 },
Point { x: 3, y: 4 }
},
expected = {3, 7}
)]
fn test_point_sum(input: Point, expected: i32) {
assert_eq!(input.x + input.y, expected);
}
高级用法
1. 使用表达式生成参数
#[parameterized(input = {
2 * 1,
2 * 2,
2 * 3
}, expected = {2, 4, 6})]
fn test_double(input: i32, expected: i32) {
assert_eq!(input, expected);
}
2. 使用范围生成参数
#[parameterized(input = 1..=5)]
fn test_is_positive(input: i32) {
assert!(input > 0);
}
3. 组合多个参数集
#[parameterized(
a = {1, 2},
b = {3, 4}
)]
fn test_multiple_params(a: i32, b: i32) {
assert!(a + b > 0);
}
与标准测试框架集成
parameterized
可以与Rust的标准测试框架无缝集成:
#[cfg(test)]
mod tests {
use super::*;
use parameterized::parameterized;
#[parameterized(input = {1, 2, 3}, expected = {2, 3, 4})]
fn test_add_one(input: i32, expected: i32) {
assert_eq!(input + 1, expected);
}
}
测试输出
运行测试时,每个参数组合会作为独立的测试用例显示:
running 3 tests
test test_add_one::case_1 ... ok
test test_add_one::case_2 ... ok
test test_add_one::case_3 ... ok
优势
- 减少重复代码:避免为相似的测试用例编写多个几乎相同的测试函数
- 提高可读性:所有测试用例集中在一个地方,便于查看和维护
- 灵活的参数组合:支持各种类型的参数和复杂的参数生成方式
parameterized
库特别适合需要测试多种输入组合的场景,如边界值测试、等价类划分测试等测试设计技术。
完整示例Demo
下面是一个完整的Rust测试模块示例,展示了如何使用parameterized库进行参数化测试:
// 在Cargo.toml中添加:
// [dev-dependencies]
// parameterized = "0.5.1"
#[cfg(test)]
mod tests {
use parameterized::parameterized;
// 1. 简单参数化测试示例
#[parameterized(input = {1, 2, 3}, expected = {2, 3, 4})]
fn test_add_one(input: i32, expected: i32) {
// 测试输入值加1是否等于预期值
assert_eq!(input + 1, expected);
}
// 2. 使用元组作为参数的示例
#[parameterized(
input = {
(1, 2),
(3, 4),
(5, 6)
},
expected = {3, 7, 11}
)]
fn test_add_tuples(input: (i32, i32), expected: i32) {
// 测试元组中两个数相加的结果
assert_eq!(input.0 + input.1, expected);
}
// 3. 使用自定义类型的示例
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
#[parameterized(
point = {
Point { x: 1, y: 2 },
Point { x: 3, y: 4 }
},
expected = {3, 7}
)]
fn test_point_sum(point: Point, expected: i32) {
// 测试Point结构体的x和y相加结果
assert_eq!(point.x + point.y, expected);
}
// 4. 高级用法:使用表达式生成参数
#[parameterized(input = {
2 * 1,
2 * 2,
2 * 3
}, expected = {2, 4, 6})]
fn test_expressions(input: i32, expected: i32) {
// 测试输入值是否等于预期值
assert_eq!(input, expected);
}
// 5. 高级用法:使用范围生成参数
#[parameterized(num = 1..=5)]
fn test_range(num: i32) {
// 测试范围内的数是否都大于0
assert!(num > 0);
}
// 6. 高级用法:组合多个参数集
#[parameterized(
a = {1, 2},
b = {3, 4}
)]
fn test_multiple_parameters(a: i32, b: i32) {
// 测试多参数组合的和是否大于0
assert!(a + b > 0);
}
}
这个完整示例展示了parameterized库的主要功能,包括:
- 基本参数化测试
- 元组参数测试
- 自定义类型测试
- 表达式生成参数
- 范围生成参数
- 多参数组合测试
要运行这些测试,只需执行常规的cargo test
命令,每个参数组合都会作为独立的测试用例运行。