Rust模糊测试宏库propfuzz-macro的使用,提升Rust代码覆盖率与漏洞检测的自动化测试工具
propfuzz-macro
propfuzz-macro 是 propfuzz 测试的 procedural macros 实现。
这个 crate 是 propfuzz
的一个实现细节,不应该直接使用。请通过 propfuzz
来使用它。
贡献
查看 CONTRIBUTING 文件了解如何参与贡献。
许可证
这个项目采用 Apache 2.0 许可证或 MIT 许可证。
安装
在你的项目目录中运行以下 Cargo 命令:
cargo add propfuzz-macro
或者在 Cargo.toml 中添加以下行:
propfuzz-macro = "0.0.1"
完整示例
以下是使用 propfuzz-macro 的完整示例代码:
// 首先需要添加 propfuzz 作为依赖
// Cargo.toml:
// [dev-dependencies]
// propfuzz = "0.0.1"
use propfuzz::prelude::*;
// 定义一个要测试的函数
fn add(a: i32, b: i32) -> i32 {
a + b
}
// 使用 propfuzz 宏创建模糊测试
#[propfuzz]
fn test_add(#[propfuzz(values = "-100..100")] a: i32, #[propfuzz(values = "-100..100")] b: i32) {
let result = add(a, b);
assert_eq!(result, a + b);
}
// 主测试函数
#[test]
fn run_propfuzz_tests() {
test_add(); // 这将运行模糊测试
}
这个示例展示了如何:
- 使用
#[propfuzz]
宏创建模糊测试 - 使用
#[propfuzz(values = "...")]
指定输入值的范围 - 对简单的加法函数进行模糊测试
注释说明:
#[propfuzz]
宏会将函数转换为模糊测试values
参数指定了输入值的生成范围- 测试函数不需要返回值,只需要包含断言
完整示例代码
// 在 Cargo.toml 中添加依赖
// [dev-dependencies]
// propfuzz = "0.0.1"
use propfuzz::prelude::*;
// 定义一个更复杂的函数进行测试
fn process_string(input: &str) -> usize {
// 简单示例:返回字符串长度
input.len()
}
// 定义字符串处理函数的模糊测试
#[propfuzz]
fn test_process_string(
#[propfuzz(values = r#""a", "abc", "hello world", ""#)] input: &str
) {
let result = process_string(input);
assert_eq!(result, input.len());
}
// 定义另一个数值处理函数
fn multiply(a: i32, b: i32) -> i32 {
a * b
}
// 数值处理函数的模糊测试
#[propfuzz]
fn test_multiply(
#[propfuzz(values = "-10..10")] a: i32,
#[propfuzz(values = "-10..10")] b: i32
) {
let result = multiply(a, b);
assert_eq!(result, a * b);
}
// 主测试函数
#[test]
fn run_all_propfuzz_tests() {
test_process_string(); // 运行字符串处理测试
test_multiply(); // 运行乘法测试
}
这个完整示例展示了:
- 如何为不同类型的函数(字符串处理和数值计算)创建模糊测试
- 如何使用字符串字面量作为测试输入值
- 如何在一个测试函数中运行多个模糊测试
- 更复杂的测试场景和断言
注释说明:
r#""a", "abc", "hello world", ""#
语法用于指定字符串测试用例- 数值范围使用
-10..10
语法指定 - 每个模糊测试函数都可以独立运行
- 主测试函数集中运行所有模糊测试
1 回复
Rust模糊测试宏库propfuzz-macro使用指南
简介
propfuzz-macro是一个结合了属性测试(property-based testing)和模糊测试(fuzzing)的Rust宏库,旨在提升Rust代码的测试覆盖率和漏洞检测能力。它通过自动生成大量随机输入来测试代码的边界条件,帮助开发者发现潜在的错误和漏洞。
主要特性
- 结合属性测试和模糊测试的优点
- 通过宏简化测试编写
- 自动生成随机输入数据
- 支持测试用例缩小(minimization)以定位问题
- 与Rust测试框架无缝集成
安装
在Cargo.toml中添加依赖:
[dependencies]
propfuzz-macro = "0.1"
完整示例demo
下面是一个完整的propfuzz-macro使用示例,演示了从基本测试到高级用法的完整流程:
// 1. 引入必要的宏和类型
use propfuzz_macro::{propfuzz, arbitrary, FuzzConfig};
use std::collections::HashMap;
// 2. 定义测试用的结构体
#[derive(Debug, Clone)]
struct User {
id: u64,
name: String,
age: u8,
}
// 3. 自定义数据生成器
#[arbitrary]
fn gen_valid_user() -> User {
User {
id: propfuzz::any::<u64>(),
name: format!("user_{}", propfuzz::any::<u16>()),
age: (propfuzz::any::<u8>() % 100) + 1, // 年龄1-100岁
}
}
// 4. 基本属性测试 - 测试加法交换律
#[propfuzz]
fn test_addition_commutative(a: i32, b: i32) {
assert_eq!(a + b, b + a);
}
// 5. 带配置的模糊测试 - 测试字符串操作
#[propfuzz(FuzzConfig {
cases: 500,
max_size: 512,
..Default::default()
})]
fn test_string_concat(s1: String, s2: String) {
let combined = s1.clone() + &s2;
assert!(combined.starts_with(&s1));
assert!(combined.ends_with(&s2));
}
// 6. 结构体测试 - 测试用户年龄验证
#[propfuzz]
fn test_user_age(user: User) {
assert!(user.age >= 1 && user.age <= 100);
}
// 7. 使用自定义生成器的测试
#[propfuzz]
fn test_valid_user(#[from(gen_valid_user)] user: User) {
assert!(!user.name.is_empty());
assert!(user.name.starts_with("user_"));
}
// 8. 结合标准测试框架 - 测试HashMap操作
#[test]
#[propfuzz]
fn test_hashmap_operations(map: HashMap<String, i32>) {
let keys: Vec<_> = map.keys().collect();
let values: Vec<_> = map.values().collect();
assert_eq!(keys.len(), values.len());
}
fn main() {
println!("propfuzz-macro示例项目");
println!("运行测试: cargo test");
}
最佳实践
- 从简单的属性开始测试,逐步增加复杂性
- 关注不变性(invariants)而非具体值
- 为失败用例添加种子(seed)以便重现
- 结合常规单元测试使用
- 对性能敏感代码设置合理的输入大小限制
故障排查
当测试失败时,propfuzz-macro会:
- 自动缩小失败用例到最小重现规模
- 显示导致失败的输入值
- 提供种子值以便重现问题
例如:
Test failed with smallest input: "a\0b"
Seed: 0x1234567890abcdef
性能考虑
- 模糊测试可能比常规测试耗时更长
- 对于大型项目,考虑在CI中并行运行测试
- 使用
FuzzConfig
调整测试用例数量和大小
propfuzz-macro通过自动化生成测试用例和检测边界条件,可以显著提高代码质量和安全性,是Rust项目测试工具箱中的有力补充。