Rust模糊测试与模拟数据生成库blurmock的使用,高效生成随机数据并支持测试场景模拟
Rust模糊测试与模拟数据生成库blurmock的使用,高效生成随机数据并支持测试场景模拟
安装
在你的项目目录中运行以下Cargo命令:
cargo add blurmock
或者在Cargo.toml中添加以下行:
blurmock = "0.1.3"
基本用法
blurmock是一个Rust库,用于高效生成随机数据并支持测试场景模拟。以下是一个基本示例:
use blurmock::*;
#[derive(Debug, Mock)]
struct User {
id: u64,
name: String,
email: String,
active: bool,
#[mock(faker="0..100")]
age: u8,
}
fn main() {
// 生成单个模拟用户
let user: User = mock!();
println!("Mock user: {:?}", user);
// 生成多个模拟用户
let users: Vec<User> = mock_vec!(3);
for user in users {
println!("User: {:?}", user);
}
}
完整示例Demo
以下是一个更完整的示例,展示如何使用blurmock进行模糊测试和场景模拟:
use blurmock::*;
// 定义一个待测试的结构体
#[derive(Debug, Mock)]
struct Order {
#[mock(faker="1..1000")]
id: u64,
customer_name: String,
#[mock(faker="10.0..1000.0")]
total_amount: f64,
#[mock(faker="vec![1, 2, 3]")]
items: Vec<u32>,
is_completed: bool,
}
// 测试函数
fn process_order(order: &Order) -> Result<(), String> {
if order.total_amount <= 0.0 {
return Err("Total amount must be positive".to_string());
}
if order.customer_name.is_empty() {
return Err("Customer name cannot be empty".to_string());
}
Ok(())
}
#[test]
fn test_order_processing() {
// 生成100个随机订单进行模糊测试
let orders: Vec<Order> = mock_vec!(100);
for order in orders {
match process_order(&order) {
Ok(_) => {
// 验证处理成功的订单满足条件
assert!(order.total_amount > 0.0);
assert!(!order.customer_name.is_empty());
}
Err(e) => {
// 验证处理失败的订单确实违反条件
assert!(
order.total_amount <= 0.0 ||
order.customer_name.is_empty(),
"Unexpected error: {}", e
);
}
}
}
}
// 自定义mock生成器示例
mod custom_mocks {
use blurmock::MockContext;
pub fn custom_status() -> String {
let statuses = vec!["pending", "shipped", "delivered", "cancelled"];
statuses[MockContext::random().gen_range(0..statuses.len())].to_string()
}
}
#[derive(Debug, Mock)]
struct Shipment {
#[mock(faker="1..1000")]
tracking_number: u64,
#[mock(using="custom_mocks::custom_status")]
status: String,
}
fn main() {
// 生成随机发货信息
let shipment: Shipment = mock!();
println!("Shipment status: {}", shipment.status);
// 生成特定条件的模拟数据
let completed_order = mock_with!(Order {
is_completed: true,
..Default::default()
});
assert!(completed_order.is_completed);
}
文档
更多详细用法和API参考请查看官方文档。
许可证
BSD-2-Clause 许可证
所有者
Attila Dusnoki (dati91)
1 回复
Rust模糊测试与模拟数据生成库blurmock使用指南
介绍
blurmock是一个Rust库,专门用于模糊测试(Fuzz Testing)和模拟数据生成。它提供了高效生成随机数据的能力,并支持测试场景的模拟,特别适合以下场景:
- 单元测试和集成测试中需要随机输入数据
- 模糊测试需要生成大量随机数据来测试程序鲁棒性
- 模拟真实世界数据分布进行压力测试
- 快速创建测试用的模拟对象(Mock objects)
主要特性
- 高性能随机数据生成
- 可配置的数据生成规则
- 支持自定义数据类型生成
- 内置常见数据模式(邮件、URL、日期等)
- 与Rust测试框架无缝集成
基本使用方法
添加依赖
首先在Cargo.toml
中添加依赖:
[dependencies]
blurmock = "0.3"
基本示例
use blurmock::prelude::*;
#[test]
fn test_random_data_generation() {
// 初始化模糊测试生成器
let mut fuzzer = Fuzzer::new();
// 生成随机字符串
let random_string: String = fuzzer.fuzz();
println!("Random string: {}", random_string);
// 生成指定长度的随机字符串
let fixed_length_string: String = fuzzer.fuzz_with_len(10);
assert_eq!(fixed_length_string.len(), 10);
// 生成随机数字
let random_number: i32 = fuzzer.fuzz();
println!("Random number: {}", random_number);
// 生成指定范围内的数字
let ranged_number: u8 = fuzzer.fuzz_in_range(0..=100);
assert!(ranged_number <= 100);
}
高级用法
自定义数据结构生成
use blurmock::prelude::*;
#[derive(Debug, Fuzz)]
struct User {
#[fuzz(pattern = "[a-z]{5,10}")]
username: String,
#[fuzz(pattern = "email")]
email: String,
#[fuzz(range = "18..=99")]
age: u8,
#[fuzz(one_of = "admin,moderator,user")]
role: String,
}
#[test]
fn test_custom_struct_generation() {
let mut fuzzer = Fuzzer::new();
let random_user: User = fuzzer.fuzz();
println!("Random user: {:?}", random_user);
assert!(random_user.age >= 18 && random_user.age <= 99);
}
模糊测试示例
use blurmock::prelude::*;
fn process_input(input: &str) -> Result<(), &'static str> {
if input.len() > 100 {
return Err("Input too long");
}
if input.contains('\0') {
return Err("Null byte not allowed");
}
Ok(())
}
#[test]
fn fuzz_test_input_processing() {
let mut fuzzer = Fuzzer::new()
.string_config(StringConfig::new().max_len(150)); // 生成稍长于限制的字符串
for _ in 0..1000 {
let input: String = fuzzer.fuzz();
let result = process_input(&input);
// 验证函数是否正确处理了边界情况
if input.len() > 100 {
assert!(result.is_err());
} else if input.contains('\0') {
assert!(result.is_err());
} else {
assert!(result.is_ok());
}
}
}
模拟测试场景
use blurmock::prelude::*;
#[derive(Debug, Fuzz)]
struct Order {
#[fuzz(range = "1..=1000")]
id: u64,
#[fuzz(pattern = "price")]
amount: f64,
#[fuzz(one_of = "pending,completed,cancelled")]
status: String,
}
#[test]
fn test_order_processing() {
let mut fuzzer = Fuzzer::new();
// 生成100个随机订单测试处理逻辑
let orders: Vec<Order> = fuzzer.fuzz_many(100);
for order in orders {
println!("Processing order: {:?}", order);
// 这里添加实际的订单处理逻辑和断言
}
}
配置选项
blurmock提供了丰富的配置选项来自定义数据生成行为:
use blurmock::{Fuzzer, StringConfig, NumberConfig};
let mut fuzzer = Fuzzer::new()
.string_config(
StringConfig::new()
.min_len(5)
.max_len(20)
.exclude_chars("\0") // 排除空字符
)
.number_config(
NumberConfig::new()
.prefer_edge_cases(true) // 优先生成边界值
);
最佳实践
- 在模糊测试中,建议运行至少1000次迭代以获得良好的覆盖率
- 对于自定义类型,使用
#[derive(Fuzz)]
可以简化实现 - 结合Rust的
proptest
库可以获得更强大的属性测试能力 - 对于关键业务逻辑,建议同时使用模糊测试和确定性测试
完整示例代码
以下是一个完整的blurmock使用示例,展示了如何创建自定义数据结构、配置生成器并进行模糊测试:
use blurmock::prelude::*;
// 自定义数据结构
#[derive(Debug, Fuzz)]
struct Product {
#[fuzz(range = "1000..=9999")]
id: u32,
#[fuzz(pattern = "[A-Z][a-z]{5,12}")]
name: String,
#[fuzz(pattern = "price")]
price: f64,
#[fuzz(one_of = "available,out_of_stock,discontinued")]
status: String,
#[fuzz(range = "0..=5")]
rating: u8,
}
// 被测函数
fn validate_product(product: &Product) -> Result<(), String> {
if product.name.len() > 20 {
return Err("Product name too long".to_string());
}
if product.price <= 0.0 {
return Err("Price must be positive".to_string());
}
Ok(())
}
#[test]
fn test_product_validation() {
// 配置模糊测试生成器
let mut fuzzer = Fuzzer::new()
.string_config(
StringConfig::new()
.min_len(5)
.max_len(25) // 故意设置比验证条件稍大
);
// 运行1000次模糊测试
for _ in 0..1000 {
let product: Product = fuzzer.fuzz();
let validation_result = validate_product(&product);
// 验证边界条件
if product.name.len() > 20 {
assert!(validation_result.is_err());
} else if product.price <= 0.0 {
assert!(validation_result.is_err());
} else {
assert!(validation_result.is_ok());
}
}
}
#[test]
fn generate_product_catalog() {
let mut fuzzer = Fuzzer::new();
// 生成50个随机产品
let products: Vec<Product> = fuzzer.fuzz_many(50);
// 打印生成的第一个产品
if let Some(first_product) = products.first() {
println!("First generated product: {:?}", first_product);
}
// 验证所有产品ID都在指定范围内
for product in &products {
assert!(product.id >= 1000 && product.id <= 9999);
assert!(product.rating <= 5);
}
}
这个完整示例展示了:
- 定义自定义数据结构并使用
#[derive(Fuzz)]
自动实现模糊测试功能 - 配置模糊测试生成器的字符串生成规则
- 实现被测函数并验证其边界条件
- 批量生成测试数据并验证其有效性