新闻详情

新闻详情

首页 / 资讯中心 / 详情

用 Hypothesis 将测试写成完整规格:以二分查找的属性测试实战为例

发布时间:2026/9/25 6:09:46来源:尧图网络
用 Hypothesis 将测试写成完整规格:以二分查找的属性测试实战为例
测试开发工具【免费下载链接】hypothesisThe property-based testing library for Python项目地址https://gitcode.com/gh_mirrors/hy/hypothesis点击查看免费下载导读当一个问题被少数几条简单属性完全规定时它的实现可能依然极其繁琐但它的测试却会变得出乎意料地容易。本文以左偏二分查找left-biased binary search为完整实例讲解如何用 Hypothesis 的given与策略组合把函数规格逐条翻译成可自动执行的属性测试同时揭示属性测试与数学证明之间的边界——低概率 bug 的存在及其发现时机并给出二次搜索这类主动制造冲突场景的增强测试技巧。读完本文你将掌握以属性充当完整规格的测试方法论并理解 Hypothesis 测试数据库ExampleDatabase如何让已发现的失败持续复现直至 bug 被修复。一、什么是完全由属性规定的程序在现实工程中多数函数的正确性定义是模糊的我们知道它应该做什么但难以用简洁的条件把它框死。但还有另一类问题——例如二分查找——其结果被几条简单属性完全规定返回值必须是一个合法的插入位置把值插入该位置后列表仍然有序插入到任何更小的位置列表都不再有序。满足这三条的实现无论内部逻辑多绕都必然是正确的。原文档强调这并不代表它们容易实现很多此类问题实际上极其难写对但意味着它们容易测试。这正是属性测试property-based testing的理想土壤属性测试不关心你打算怎么做只关心结果必须满足什么。Hypothesis 的核心主张正是围绕这一点展开——它把生成输入、验证属性变成了一条流水线。二、用 Hypothesis 把规格写成测试原文档给出了一组直接对应上述三条属性的测试。下面的代码做了少量现代化处理以st.lists(st.integers())的写法给出功能与原版一致from hypothesis import given, strategies as st given(st.lists(st.integers()).map(sorted), st.integers()) def test_binary_search_gives_valid_index(ls, v): i binary_search(ls, v) assert 0 i len(ls) given(st.lists(st.integers()).map(sorted), st.integers()) def test_inserting_at_binary_search_remains_sorted(ls, v): i binary_search(ls, v) ls.insert(i, v) assert sorted(ls) ls given(st.lists(st.integers()).map(sorted), st.integers()) def test_inserting_at_smaller_index_gives_unsorted(ls, v): for i in range(binary_search(ls, v)): ls2 list(ls) ls2.insert(i, v) assert sorted(ls2) ! ls三个测试逐条对应规格的三条属性返回合法索引、在该索引插入后仍有序、在更小索引插入则失序。若三者全部通过binary_search的规格就被完整覆盖了。2.1 从源码看given与策略组合这一组测试的核心设施都有明确的源码依据given是 Hypothesis 测试的主入口。在 core.py 中given的文档字符串明确写道Thegivendecorator turns a function into a Hypothesis test. This is the main entry point to Hypothesis. 它既支持位置参数也支持关键字参数并且从右往左填充参数——这意味着放在最左边的位置参数可以留给self便于在unittest.TestCase子类或实例方法中使用这一行为在该段源码的注释中有直接说明。st.integers()生成整数。见 numbers.pyintegers(min_valueNone, max_valueNone)当上下界为None时不设边界其 docstring 指出例子会向 0 收缩负数还会向正数收缩。这正是 Hypothesis 失败用例会自动变小、便于阅读的根本原因。st.lists()生成列表。见 core.pylists(elements, *, min_size0, max_sizeNone, unique_byNone, uniqueFalse)长度落在[min_size, max_size]且通过尝试移除元素来收缩。结合.map(sorted)收缩得到的仍然是有序列表——这与 Hypothesis 将收缩集成进生成的设计一脉相承可对照 integrated-shrinking 一文 中收缩必须满足与生成相同的约束的论述。因此st.lists(st.integers()).map(sorted)的含义是先随机生成任意长度、任意整数的列表再映射为有序列表作为测试输入一旦断言失败Hypothesis 会尝试把这个有序列表收缩到最小反例。三、测试与数学证明的边界低概率 bug 的存在如果这些测试通过我们的实现一定完全正确对吧原文档给出的回答是大多数情况下是但存在一个反复出现的隐患——属性测试无法保证属性在所有输入上都成立。证明给出的是全称保证这些属性总是成立而测试只能保证在被检查的有限样本上成立。Hypothesis 的检查范围远超手写测试但终究是有限集合。差异带来的直接后果就是低概率 bug某个错误行为只有在相当特殊的输入上才会被触发随机生成往往需要多次运行才能撞上。原文档随后给出了一个恰好踩中该陷阱的实现def binary_search(list, value): if not list: return 0 if value list[-1]: return len(list) if value list[0]: return 0 lo 0 hi len(list) - 1 while lo 1 hi: mid (lo hi) // 2 pivot list[mid] if value pivot: hi mid elif value pivot: return mid else: lo mid return hi这个实现犯了一个经典的错误当mid处的元素恰好等于目标值时直接返回mid。这违反了永远返回最小插入位置的第三条属性——[0, 1, 1, 1, 1]中插入1时正确结果应为1而该实现可能在mid 2或更晚时提前返回。3.1 为什么这个 bug 难以被随机撞上原文档给出的失败用例是Failing test case: test_inserting_at_smaller_index_gives_unsorted( ls[0, 1, 1, 1, 1], v1 )有时也会得到ls[-1, 0, 0, 0, 0], v0。触发条件相当苛刻value必须在ls中至少出现两次并且二分过程中某个非首个出现位置恰好被选为mid。Hypothesis 的生成器会刻意提高这种用例出现的概率但提升幅度有限——作者实测通常需要运行 2 到 5 次才会失败一次。这一案例很好地说明了属性测试方法论的一个核心权衡规格完备 ≠ 反例易得。三条属性虽然共同构成了完整规格但第三条属性对重复元素这类特定输入特别敏感而重复元素在完全随机的列表中并不常见。四、失败之后Hypothesis 测试数据库的自动接力原文档接着指出一旦测试开始失败Hypothesis 的测试数据库就会接管让该测试持续失败直到 bug 被修复。这在源码中有完整的对应实现。见 database.pyExampleDatabase的类文档写道——Hypothesis 会自动把失败保存到settings.database指向的数据库中下次运行同一测试时会在reuse阶段重放这些失败对应Phase.reuse。数据库最好被理解为永远不需要失效的缓存。具体机制包括save(key, value)把失败的例子保存到数据库database.pyfetch(key)按测试标识读取已保存的例子database.py运行阶段由Phase枚举驱动explicit显式example、reuse重放数据库中的失败、generate生成新例子等见 _settings.py。于是实际开发体验是低概率 bug 一旦被首次捕获后续每次运行都会先重放该反例持续红灯直到修复。但正如原文档强调的这并不能消除低概率失败的全部成本——它把发现问题的时间点从引入 bug 之时推迟到了某次偶然撞上之时而推迟越久定位成本越高。这在状态化测试中尤为突出由于搜索空间巨大存在大量低概率 bug见 rule-based-stateful-testing 一文对应源码中的RuleBasedStateMachine见 stateful.py。五、修复策略主动制造冲突场景而非被动等待幸运的是这类问题有一个简洁的修复路径编写对示例不敏感的增强测试——不依赖 Hypothesis 恰好生成重复元素而是由测试自身主动制造出容易出问题的结构。原文档给出的方案是搜索—插入—再搜索given(st.lists(st.integers()).map(sorted), st.integers()) def test_inserting_at_result_point_and_searching_again(ls, v): i binary_search(ls, v) ls.insert(i, v) assert binary_search(ls, v) i其正确性论证非常优雅先搜索、在结果位置插入、再搜索一次插入点不可能移动——因为在该位置再插一次结果依然有序而在任何更早位置插入依然失序所以第二次搜索必然返回同一个位置。这个测试几乎稳定失败于那个错误实现因为它不再依赖随机数据里碰巧存在重复而是主动创造了重复把v插回ls恰好制造出一个紧邻的重复对而这样的重复对极可能落在二分查找的探查路径上。这正是原文档提出的核心技巧——用输出引导输入的构造让测试主动把数据推向最可能暴露错误的形态。5.1 与测试优化器方法论的呼应原文档特别提醒读者这个思路与作者此前在 testing-optimizers-with-hypothesis 一文 中使用的技巧同源那里不是直接断言最优解因为无对照而是测试对扰动的正确响应——移除一个已选物品不应改善得分、添加一个已选物品的副本不应降低得分。文章中还展示了用st.data()在测试运行时交互式取数data.draw(st.sampled_from(original_solution))让后续输入依赖函数输出从而构造出最能检验性质的数据。两条方法论的共同点是当完全规格难以直接验证时就验证规格在结构化变更下的不变量。对于二分查找插入后再次搜索位置不变就是这样一个对变更的响应断言对于背包问题增删物品后得分不反向变化也是。这种思路可以推广到更广阔的领域——例如修改用户权限或系统设置后断言其可用选项集合单调不减。六、结论规格测试是起点而非终点原文档以三条结论收尾这里结合全文展开完全规定的程序是属性测试的天然富矿。规格即测试每条属性都可以用 Hypothesis 的given与策略组合直接翻译成自动化断言几乎无需手工构造用例。这是测试的起点而不是终点。属性测试与数学证明之间存在本质差异——前者只能保证有限样本上的正确性。低概率 bug 会真实存在需要开发者继续思考还有哪些有趣的方式去测试软件例如主动制造重复、利用输出构造扰动输入、做状态化测试等。善用 Hypothesis 的失败接力机制。一旦反例出现ExampleDatabase会在reuse阶段自动重放让 bug 持续暴露直至修复而为了尽早发现问题则应主动编写对示例不敏感的增强测试把发现失败的时机从偶然拉回必然。延伸阅读rule-based-stateful-testing状态化测试中的低概率 bug 问题testing-optimizers-with-hypothesis以对扰动的正确响应测试优化器的完整实例integrated-shrinkingHypothesis 将收缩集成进生成的设计理念核心源码given 定义、integers 策略、lists 策略、ExampleDatabase、Phase 枚举。赞分享测试开发工具【免费下载链接】hypothesisThe property-based testing library for Python项目地址https://gitcode.com/gh_mirrors/hy/hypothesis点击查看免费下载相关推荐用 Hypothesis 守护 Encode/Decode 不变量以 Run Length Encoding 为例的属性测试实战用 Hypothesis 守护 Encode/Decode 不变量以 Run Length Encoding 为例的属性测试实战 导读不变量invaria测试开发工具Hypothesis 属性测试入门从「写例子」到「描述性质」的测试革命Hypothesis 属性测试入门从「写例子」到「描述性质」的测试革命 Hypothesis 是 Python 生态中最具代表性的属性测试property测试开发工具用 Hypothesis 属性化测试覆盖配置参数以 Argon2 密码哈希库为例用 Hypothesis 属性化测试覆盖配置参数以 Argon2 密码哈希库为例 配置参数测试是软件测试中极易被忽视、却又极易出错的一环。本文基于 Hypot测试开发工具上一篇Tutti安全架构分析如何在多代理环境中保护用户数据和隐私下一篇AI Job Search命令大全掌握所有实用功能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

中秋国庆远程办公怎么办 中秋国庆远程办公软件怎么选 2026/9/25 7:21:13

中秋国庆远程办公怎么办 中秋国庆远程办公软件怎么选

中秋国庆远程办公,是不少职场人长假期间的常态,临时对接工作、处理紧急工单,却常被远控工具卡顿难用的问题困扰。中秋国庆远程办公想要高效不折腾,无需留守公司工位,无界趣连2.0就能轻松搞定各类异地办公需求&#xff…

阅读更多 →
用ps ax读懂Linux进程状态与调度器核心逻辑 2026/9/25 7:21:06

用ps ax读懂Linux进程状态与调度器核心逻辑

凌晨两点半,群里突然炸了。一台线上机器CPU跑到800%,监控大屏飘红,值班同事接连被抖醒。我登录服务器后没急着开top,第一件事是敲了一行命令:ps ax。为什么不是top?因为top是动态刷新加瞬时快照&#xff0c…

阅读更多 →
CodeCombat AP CSP Explore 任务教学指南:基于计算创新的影响开展 Performance Task 演练 2026/9/25 7:21:06

CodeCombat AP CSP Explore 任务教学指南:基于计算创新的影响开展 Performance Task 演练

游戏开发教育前端后端 【免费下载链接】codecombat Game for learning how to code. 项目地址: https://gitcode.com/gh_mirrors/co/codecombat 点击查看 免费下载 导读 本文围绕 CodeCombat 的 AP 计算机科学原理(AP CS Principles, AP CSP&#xff0…

阅读更多 →
Apache DataFusion 52.4.0 更新深度解读:array_sort 空值语义修复、SMJ 行数缓存与动态过滤下推收紧等 11 项变更 2026/9/25 7:21:06

Apache DataFusion 52.4.0 更新深度解读:array_sort 空值语义修复、SMJ 行数缓存与动态过滤下推收紧等 11 项变更

大数据数据分析后端 【免费下载链接】datafusion Apache DataFusion SQL Query Engine 项目地址: https://gitcode.com/gh_mirrors/datafu/datafusion 点击查看 免费下载 本文基于 Apache DataFusion 52.4.0 官方变更日志(dev/changelog/52.4.0.md&…

阅读更多 →
F´ Topology 构建指南:从组件实例化、端口互连到活动组件任务启动的完整流程 2026/9/25 7:21:06

F´ Topology 构建指南:从组件实例化、端口互连到活动组件任务启动的完整流程

嵌入式系统编程 【免费下载链接】fprime F - A flight software and embedded systems framework 项目地址: https://gitcode.com/gh_mirrors/fp/fprime 点击查看 免费下载 本文以 F(F Prime)飞控软件与嵌入式系统框架为背景,系统…

阅读更多 →
ctf-wiki 内核利用实战:ret2usr 攻击手法解析——以 2018 强网杯 core 为例 2026/9/25 7:21:00

ctf-wiki 内核利用实战:ret2usr 攻击手法解析——以 2018 强网杯 core 为例

文档网络安全教程 【免费下载链接】ctf-wiki Come and join us, we need you! 项目地址: https://gitcode.com/gh_mirrors/ct/ctf-wiki 点击查看 免费下载 导读 ret2usr(return to user space)是 Linux 内核 pwn 中一种经典的控制流劫持提权…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉