property-based-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseProperty-Based Testing
基于属性的测试(Property-Based Testing,PBT)
Overview
概述
Property-based testing (PBT) generates random inputs and verifies that properties hold for all of them. Instead of testing specific examples, you test invariants.
When PBT beats example-based tests:
- Serialization pairs (encode/decode)
- Pure functions with clear contracts
- Validators and normalizers
- Data structure operations
基于属性的测试(PBT)会生成随机输入,并验证所有输入是否都满足特定属性。与测试特定示例不同,你测试的是不变量。
PBT优于基于示例的测试的场景:
- 序列化对(编码/解码)
- 具有明确契约的纯函数
- 验证器和规范化器
- 数据结构操作
Property Catalog
属性目录
| Property | Formula | When to Use |
|---|---|---|
| Roundtrip | | Serialization, conversion pairs |
| Idempotence | | Normalization, formatting, sorting |
| Invariant | Property holds before/after | Any transformation |
| Commutativity | | Binary/set operations |
| Associativity | | Combining operations |
| Identity | | Operations with neutral element |
| Inverse | | encrypt/decrypt, compress/decompress |
| Oracle | | Optimization, refactoring |
| Easy to Verify | | Complex algorithms |
| No Exception | No crash on valid input | Baseline (weakest) |
Strength hierarchy (weakest to strongest):
No Exception -> Type Preservation -> Invariant -> Idempotence -> RoundtripAlways aim for the strongest property that applies.
| 属性 | 公式 | 适用场景 |
|---|---|---|
| 往返一致性(Roundtrip) | | 序列化、转换对 |
| 幂等性(Idempotence) | | 规范化、格式化、排序 |
| 不变性(Invariant) | 属性在转换前后保持成立 | 任何转换操作 |
| 交换性(Commutativity) | | 二元/集合操作 |
| 结合性(Associativity) | | 组合操作 |
| 恒等性(Identity) | | 包含中性元素的操作 |
| 逆运算(Inverse) | | 加密/解密、压缩/解压缩 |
| 参照验证(Oracle) | | 优化、重构 |
| 易验证性(Easy to Verify) | | 复杂算法 |
| 无异常(No Exception) | 合法输入下无崩溃 | 基线测试(最弱要求) |
强度层级(从弱到强):
No Exception -> Type Preservation -> Invariant -> Idempotence -> Roundtrip始终优先选择适用的最强属性。
Pattern Detection
模式检测
Use PBT when you see:
| Pattern | Property | Priority |
|---|---|---|
| Roundtrip | HIGH |
| Roundtrip | HIGH |
| Pure functions with clear contracts | Multiple | HIGH |
| Idempotence | MEDIUM |
| Valid after normalize | MEDIUM |
| Sorting, ordering, comparators | Idempotence + ordering | MEDIUM |
| Custom collections (add/remove/get) | Invariants | MEDIUM |
| Builder/factory patterns | Output invariants | LOW |
当你遇到以下模式时使用PBT:
| 模式 | 属性 | 优先级 |
|---|---|---|
| 往返一致性 | 高 |
| 往返一致性 | 高 |
| 具有明确契约的纯函数 | 多个属性 | 高 |
| 幂等性 | 中 |
带规范化器的 | 规范化后验证通过 | 中 |
| 排序、排序规则、比较器 | 幂等性 + 排序性 | 中 |
| 自定义集合(添加/删除/获取) | 不变性 | 中 |
| 构建器/工厂模式 | 输出不变性 | 低 |
When NOT to Use
不适用场景
- Simple CRUD without transformation logic
- UI/presentation logic
- Integration tests requiring complex external setup
- Code with side effects that cannot be isolated
- Prototyping where requirements are fluid
- Tests where specific examples suffice and edge cases are understood
- 无转换逻辑的简单CRUD操作
- UI/展示层逻辑
- 需要复杂外部环境配置的集成测试
- 无法隔离副作用的代码
- 需求频繁变动的原型开发
- 特定示例已足够且边缘情况已明确的测试
Library Quick Reference
库快速参考
| Language | Library | Import |
|---|---|---|
| Python | Hypothesis | |
| TypeScript/JS | fast-check | |
| Rust | proptest | |
| Go | rapid | |
| Java | jqwik | |
| Haskell | QuickCheck | |
For library-specific syntax and patterns: Use to get current documentation.
@ed3d-research-agents:internet-researcher| 语言 | 库 | 导入语句 |
|---|---|---|
| Python | Hypothesis | |
| TypeScript/JS | fast-check | |
| Rust | proptest | |
| Go | rapid | |
| Java | jqwik | |
| Haskell | QuickCheck | |
如需库的特定语法和模式: 使用获取最新文档。
@ed3d-research-agents:internet-researcherInput Strategy Best Practices
输入策略最佳实践
-
Constrain early: Build constraints INTO the strategy, not via
assume()python# GOOD st.integers(min_value=1, max_value=100) # BAD - high rejection rate st.integers().filter(lambda x: 1 <= x <= 100) -
Size limits: Prevent slow testspython
st.lists(st.integers(), max_size=100) st.text(max_size=1000) -
Realistic data: Match real-world constraintspython
st.integers(min_value=0, max_value=150) # Real ages, not arbitrary ints -
Reuse strategies: Define once, use across testspython
valid_users = st.builds(User, ...) @given(valid_users) def test_one(user): ... @given(valid_users) def test_two(user): ...
-
尽早约束: 将约束直接内置到策略中,而非使用
assume()python# GOOD st.integers(min_value=1, max_value=100) # BAD - 高拒绝率 st.integers().filter(lambda x: 1 <= x <= 100) -
大小限制: 避免测试过慢python
st.lists(st.integers(), max_size=100) st.text(max_size=1000) -
真实数据: 匹配真实世界的约束python
st.integers(min_value=0, max_value=150) # 真实年龄范围,而非任意整数 -
复用策略: 定义一次,跨测试使用python
valid_users = st.builds(User, ...) @given(valid_users) def test_one(user): ... @given(valid_users) def test_two(user): ...
Settings Guide
配置指南
python
undefinedpython
undefinedDevelopment (fast feedback)
开发环境(快速反馈)
@settings(max_examples=10)
@settings(max_examples=10)
CI (thorough)
CI环境(全面测试)
@settings(max_examples=200)
@settings(max_examples=200)
Nightly/Release (exhaustive)
夜间/发布版本( exhaustive测试)
@settings(max_examples=1000, deadline=None)
undefined@settings(max_examples=1000, deadline=None)
undefinedQuality Checklist
质量检查清单
Before committing PBT tests:
- Not tautological (assertion doesn't compare same expression)
- Strong assertion (not just "no crash")
- Not vacuous (inputs not over-filtered by )
assume() - Edge cases covered with explicit examples ()
@example - No reimplementation of function logic in assertion
- Strategy constraints are realistic
- Settings appropriate for context
提交PBT测试前需检查:
- 非同义反复(断言不是比较相同表达式)
- 强断言(不只是“无崩溃”)
- 非空泛(输入未被过度过滤)
assume() - 用显式示例覆盖边缘情况()
@example - 断言中未重实现函数逻辑
- 策略约束符合实际
- 配置符合场景需求
Red Flags
危险信号
- Tautological: tests nothing
assert sorted(xs) == sorted(xs) - Only "no crash": Always look for stronger properties
- Vacuous: Multiple calls filter out most inputs
assume() - Reimplementation: if that's how add is implemented
assert add(a, b) == a + b - Missing edge cases: No ,
@example([])decorators@example([1]) - Overly constrained: Many calls means redesign the strategy
assume()
- 同义反复: 未测试任何内容
assert sorted(xs) == sorted(xs) - 仅测试“无崩溃”: 始终寻找更强的属性
- 空泛测试: 多个调用过滤掉大部分输入
assume() - 重实现逻辑: 如果的实现就是
add(a,b),那么a+b毫无意义assert add(a, b) == a + b - 缺少边缘情况: 未添加、
@example([])等装饰器@example([1]) - 过度约束: 多个调用意味着需要重新设计策略
assume()
Common Mistakes
常见错误
| Mistake | Fix |
|---|---|
| Testing mock behavior | Test real behavior |
| Reimplementing function in test | Use algebraic properties |
| Filtering with assume() | Build constraints into strategy |
| No edge case examples | Add @example decorators |
| One property only | Add multiple properties (length, ordering, etc.) |
| 错误 | 修复方案 |
|---|---|
| 测试Mock行为 | 测试真实行为 |
| 在测试中重实现函数逻辑 | 使用代数属性 |
用 | 将约束内置到策略中 |
| 无边缘情况示例 | 添加 |
| 仅测试单个属性 | 添加多个属性(长度、排序性等) |