基于属性的测试Skill property-based-testing

这个技能提供基于属性的测试指南,帮助开发者在编写测试时覆盖序列化、验证、解析等复杂模式,通过自动生成输入和验证属性来提高代码质量和发现边缘情况。关键词包括:属性基测试、测试策略、代码验证、测试自动化、序列化测试、智能合约测试。

测试 0 次安装 0 次浏览 更新于 3/14/2026

name: 基于属性的测试 description: 提供跨多种语言和智能合约的基于属性的测试指导。适用于编写测试、审查包含序列化/验证/解析模式的代码、设计功能,或在基于属性的测试能提供比基于示例的测试更强覆盖时使用。

基于属性的测试指南

在开发过程中,当遇到基于属性的测试能提供更强覆盖的模式时,主动使用此技能。

何时调用(自动检测)

在检测到以下情况时调用此技能:

  • 序列化对encode/decodeserialize/deserializetoJSON/fromJSONpack/unpack
  • 解析器:URL解析、配置解析、协议解析、字符串到结构化数据
  • 规范化normalizesanitizecleancanonicalizeformat
  • 验证器is_validvalidatecheck_*(尤其是与规范化器结合)
  • 数据结构:具有add/remove/get操作的自定义集合
  • 数学/算法:纯函数、排序、排序、比较器
  • 智能合约:Solidity/Vyper合约、令牌操作、状态不变量、访问控制

按模式优先级:

模式 属性 优先级
编码/解码对 往返
纯函数 多重
验证器 规范化后有效
排序/排序 幂等性 + 排序
规范化 幂等性
构建器/工厂 输出不变量
智能合约 状态不变量

何时不使用

不要将此技能用于:

  • 没有转换逻辑的简单CRUD操作
  • 一次性脚本或临时代码
  • 无法隔离副作用的代码(网络调用、数据库写入)
  • 特定示例案例足够且边缘情况已充分理解的测试
  • 集成或端到端测试(基于属性的测试最适合单元/组件测试)

属性目录(快速参考)

属性 公式 何时使用
往返 decode(encode(x)) == x 序列化、转换对
幂等性 f(f(x)) == f(x) 规范化、格式化、排序
不变量 属性在前后保持不变 任何转换
交换性 f(a, b) == f(b, a) 二进制/集合操作
结合性 f(f(a,b), c) == f(a, f(b,c)) 组合操作
同一性 f(x, identity) == x 具有中性元素的操作
f(g(x)) == x 加密/解密、压缩/解压缩
参考 new_impl(x) == reference(x) 优化、重构
易于验证 is_sorted(sort(x)) 复杂算法
无异常 有效输入时无崩溃 基线属性

强度层次(从弱到强): 无异常 → 类型保持 → 不变量 → 幂等性 → 往返

决策树

基于当前任务,阅读相应部分:

任务:编写新测试
  → 阅读 [{baseDir}/references/generating.md]({baseDir}/references/generating.md)(测试生成模式和示例)
  → 然后 [{baseDir}/references/strategies.md]({baseDir}/references/strategies.md)(如果输入生成复杂)

任务:设计新功能
  → 阅读 [{baseDir}/references/design.md]({baseDir}/references/design.md)(属性驱动开发方法)

任务:代码难以测试(混合I/O、缺少逆操作)
  → 阅读 [{baseDir}/references/refactoring.md]({baseDir}/references/refactoring.md)(可测试性重构模式)

任务:审查现有的基于属性的测试
  → 阅读 [{baseDir}/references/reviewing.md]({baseDir}/references/reviewing.md)(质量检查清单和反模式)

任务:测试失败,需要解释
  → 阅读 [{baseDir}/references/interpreting-failures.md]({baseDir}/references/interpreting-failures.md)(故障分析和错误分类)

任务:需要库参考
  → 阅读 [{baseDir}/references/libraries.md]({baseDir}/references/libraries.md)(按语言的基于属性测试库,包括智能合约工具)

如何建议基于属性的测试

在编写测试时检测到高价值模式时,将基于属性的测试作为选项提供

“我注意到 encode_message/decode_message 是一个序列化对。使用基于属性的测试与往返属性将提供比示例测试更强的覆盖。需要我采用这种方法吗?”

如果代码库已使用基于属性测试库(如Hypothesis、fast-check、proptest、Echidna),更直接地说:

“这个代码库使用Hypothesis。我将使用基于属性的测试为这个序列化对编写往返属性测试。”

如果用户拒绝,编写良好的基于示例的测试,无需进一步提示。

何时不使用基于属性的测试

  • 没有复杂验证的简单CRUD
  • UI/展示逻辑
  • 需要复杂外部设置的集成测试
  • 需求流动的原型设计
  • 用户明确要求仅使用基于示例的测试

红旗

  • 推荐琐碎的getter/setter
  • 缺少配对操作(编码没有解码)
  • 忽略类型提示(类型良好 = 更容易测试)
  • 用候选人淹没用户(限制到前5-10个)
  • 在用户拒绝后强行推进

拒绝的合理化

不接受这些捷径:

  • “示例测试足够好” - 如果涉及序列化/解析/规范化,基于属性的测试能发现示例遗漏的边缘情况
  • “函数很简单” - 具有复杂输入域(字符串、浮点数、嵌套结构)的简单函数最能从基于属性测试中受益
  • “我们没有时间” - 基于属性测试通常比全面的示例套件更短
  • “编写生成器太难” - 大多数基于属性测试库都有优秀的内置策略;很少需要自定义生成器
  • “测试失败,所以是错误” - 失败需要验证;请见interpreting-failures.md
  • “没有崩溃意味着工作正常” - "无异常"是最弱的属性;始终推动更强的保证