第一个 property test 用 rc::check 声明不变式,如验证 sort 不改变容器大小,需明确参数类型、用 RC_ASSERT、避免未捕获变量或模板推导失败。

rapidcheck 用法:怎么写第一个 property test
rapidcheck 是 C++ 里最接近 Haskell QuickCheck 的库,核心是 rc::check 函数,它接收一个谓词(返回 bool 的 lambda),自动构造输入并验证是否恒真。别直接套用单元测试思维——你不是测“某个输入得到某个输出”,而是声明“对所有合法输入,某条不变式必须成立”。
常见错误现象:rc::check 报 Failed (after 12 tests) 却没打印反例;或测试直接跳过,提示 No properties found——通常是因为 lambda 没捕获必要变量,或函数签名没被正确推导。
- 确保 lambda 参数类型明确,比如用
int、std::string、std::vector<int>,避免模板参数推导失败 - 用
RC_ASSERT替代assert或EXPECT_TRUE,否则 rapidcheck 无法捕获失败上下文 - 若被测函数抛异常,需在 lambda 内显式处理,否则测试会中止而非标记为失败
示例:验证 std::sort 不改变容器大小
rc::check("sort preserves size", []() {
auto vec = *rc::gen::container<std::vector<int>>(rc::gen::arbitrary<int>());
auto original_size = vec.size();
std::sort(vec.begin(), vec.end());
RC_ASSERT(vec.size() == original_size);
});
autocheck 为什么基本不推荐在新项目里用
autocheck 是个更老的 C++ 属性测试库,依赖 Boost.Preprocessor 和大量宏,生成的测试代码可读性差,且多年未维护。它的 AUTO_CHECK 宏展开后难以调试,IDE 基本无法跳转到具体断言位置。
立即学习“C++免费学习笔记(深入)”;
使用场景仅限于:已有重度依赖 autocheck 的遗留项目,且团队不愿/不能升级工具链。新项目选 rapidcheck 或干脆用 doctest + 手动构造边界样例更可控。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 编译失败常报错在
autocheck/detail/...内部头文件,错误信息指向宏展开中间层,和你的代码无关 - 不支持自定义生成器(generator),所有输入都靠内置的
arbitrary<T>,对自定义类几乎无效 - C++17 及以上标准下,部分模板推导逻辑失效,需手动补全
decltype或冗余类型标注
如何让 rapidcheck 生成有意义的测试数据
默认的 rc::gen::arbitrary<T>() 对基础类型还行,但对业务结构体、带约束的容器(如“非空 vector”、“正整数”)会生成大量无效输入,导致测试快速失败或漏覆盖。
性能影响明显:如果生成器反复产出非法值再被 RC_PRE 过滤,rapidcheck 可能因重试超限而跳过大量测试用例。
- 用
rc::gen::filter限定范围,比如rc::gen::filter([](int x) { return x > 0; }, rc::gen::inRange(-100, 100)) - 对自定义类型,特化
rc::Arbitrary<MyStruct>::generate,别依赖默认推导 - 避免在生成器里做耗时操作(如文件读取、网络请求),rapidcheck 会在每轮测试前多次调用生成器
示例:只生成长度 ≥ 1 的字符串
auto nonEmptyString = rc::gen::filter(
[](const std::string& s) { return !s.empty(); },
rc::gen::string()
);
CI 环境下 rapidcheck 测试不稳定怎么办
本地跑通、CI 上偶尔失败,大概率是种子(seed)没固定,或生成器引入了隐式依赖(如系统时间、内存地址)。rapidcheck 默认每次运行用不同随机种子,便于发现边缘 case,但 CI 需要可重现性。
兼容性影响:某些 Linux 发行版的 glibc 版本会影响 std::hash 行为,间接导致容器遍历顺序变化,如果断言依赖顺序(如 std::set 迭代结果),就会偶发失败。
- 加
--rc-seed=12345到测试命令行,或代码里调用rc::setSeed(12345) - 避免断言容器迭代顺序,改用
std::is_permutation或集合语义比较 - 禁用模糊测试模式(
--rc-tests=100而非默认的--rc-tests=0),防止因资源限制中途截断
容易被忽略的是:rapidcheck 在 fork 后的子进程中可能继承父进程 seed,若测试框架本身做了 fork(如某些 sanitizer 模式),需主动重置 seed。


















