如何在Rust的proptest中从特定种子运行,实现类似Hypothesis的@reproduce_failure功能?
Rust的proptest库如何复现测试失败?
proptest 有内置的失败复现机制,不需要额外装饰器,同时也可以借助serde实现更灵活的自定义持久化方案,具体如下:
内置方案:通过环境变量复用失败种子
当测试失败时,proptest会在控制台输出包含PROPTEST_CASE的提示,类似:
thread 'test::my_test' panicked at 'test failed', src/test.rs:42:9 note: run with `PROPTEST_CASE=xxxx` environment variable to reproduce
你只需要在运行测试时设置这个环境变量,就能精准复现那次失败的用例:
PROPTEST_CASE=xxxx cargo test my_test -- --nocapture
这个机制完全适配“测试→调试修复→排查下一个失败”的流程,和Hypothesis的@reproduce_failure作用一致。
借助serde自定义持久化方案
如果需要把失败案例持久化到文件(比如长期保存或跨环境调试),可以用serde序列化测试输入:
- 先在
Cargo.toml添加依赖:
[dependencies] proptest = "1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0"
- 编写测试代码,失败时保存案例,或加载已有案例调试:
use proptest::prelude::*; use serde::{Serialize, Deserialize}; use std::fs::{self, File}; use std::io::Write; #[derive(Debug, Clone, Serialize, Deserialize)] struct TestInput { value: u32, name: String, } fn test_input_strategy() -> impl Strategy<Value = TestInput> { (0..1000, "[a-z]+".prop_map(String::from)).prop_map(|(value, name)| TestInput { value, name }) } proptest! { #[test] fn my_test(input in test_input_strategy()) { // 模拟失败条件 if input.value == 42 && input.name == "foo" { // 序列化并保存失败案例 let json = serde_json::to_string_pretty(&input).unwrap(); fs::write("failed_case.json", json).unwrap(); panic!("test failed with input: {:?}", input); } } } // 专门用于调试的测试函数 #[test] fn debug_saved_case() { let json = fs::read_to_string("failed_case.json").unwrap(); let input: TestInput = serde_json::from_str(&json).unwrap(); // 直接执行测试逻辑,方便用调试器断点排查 assert_ne!(input.value, 42, "value should not be 42"); assert_ne!(input.name, "foo", "name should not be foo"); }
这样每次失败都会把触发问题的输入保存到文件,后续运行debug_saved_case就能直接加载该案例,不用反复执行模糊测试来复现问题。
内容的提问来源于stack exchange,提问作者Dimitrius
相关产品推荐
相关产品推荐

