首页/开发/软件测试速查/基于属性的测试(Property-Based Testing)
测试基础与分层67 条

基于属性的测试(Property-Based Testing)

描述对任意输入都成立的性质(如编码解码后等价),由框架生成大量随机输入并自动缩减反例;由 QuickCheck(Haskell)开创。

软件测试速查开发更新于 2026-10-13

属性测试是什么

属性测试(property-based testing)不写具体输入输出,而是声明「对所有合法输入都应成立的性质」:排序结果有序、编解码互逆、操作幂等。框架自动生成成百上千组输入寻找反例,失败后自动收缩(shrink)到最小反例。示例测试测你想得到的边界,属性测试测你没想到的组合。

基本信息

Pythonhypothesis:@given 加 strategies 描述输入分布
Javajqwik 等支持属性与收缩
JavaScriptfast-check 面向 JS/TS
常见性质不变量、互逆(编码解码)、幂等、参照模型对照
失败处理自动收缩输出最小反例,附随机种子便于复现
状态机测试对命令序列建模,验证状态流转的通用性质

最小示例

最小示例
from hypothesis import given, strategies as st
import json

@given(st.text())
def test_json_roundtrip(s):            # 性质:编解码互逆
    assert json.loads(json.dumps(s)) == s

@given(st.lists(st.integers()))
def test_sorted_is_ordered(xs):        # 性质:结果有序
    ys = sorted(xs)
    assert all(a <= b for a, b in zip(ys, ys[1:]))

典型使用场景

  • 算法与工具函数:排序、解析、编解码的正确性验证
  • 序列化兼容:旧版本代码能解析新版本数据
  • 数值边界:自动覆盖极值、零、负数等组合
  • 状态机:订单状态流转、会话管理的过程性验证
  • 与示例测试组双层网:示例抓已知场景,属性扫未知区域

四个概念怎么理解

概念含义注意
property对所有合法输入成立的性质写错会误报或漏报
strategy描述输入如何生成约束过宽会产出无效用例
shrink失败后收缩到最小反例最小反例是修 bug 的入口
seed随机种子固定种子复现,定期放开探索
性质要先拿已知实现验证再上线:性质写错(过强)会让测试常红,浪费时间;写弱(接近恒真)则测不出东西。
生成数据用约束贴近业务分布:纯随机整数常远离业务范围,加最小值、最大值与结构化策略。
失败后把最小反例固化成示例用例再修代码:否则修完没有回归防线,同类问题可能再次溜进来。

易错点

  • 把属性测试写成固定输出断言:生成再多输入也只是重复示例测试,完全没用上性质的力量
  • 忽略收缩结果直接用原始反例:几百行输入没法学,先看 shrink 后的最小例
  • 生成器不加约束:大量无效输入导致测试常红或常绿,先收紧策略
  • CI 永远固定单一种子:探索能力归零,定期让种子放开收集新反例

数据来源与参考

  • Hypothesis 官方文档(hypothesis.readthedocs.io)
  • Claessen & Hughes《QuickCheck》(2000)
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌