可组合测试
摘要
这篇文章讨论了软件测试中的可组合测试,解释了如何通过组合测试来提高可读性、可维护性和效率,同时保持隔离性和特异性等属性。
暂无内容
查看缓存全文
缓存时间: 2026/08/18 16:01
# 组合式测试
来源:https://newsletter.kentbeck.com/p/composable-tests
测试期望特性中包含12项测试属性,其中两项是:
- 隔离性——运行单个测试的结果应完全独立于其他测试的结果。
- 组合性——??? 测试应可一起运行 ??? 这难道不就是隔离性吗?
并非如此,原因如下(我终于找到了示例——示例总是最难的部分)。
如果测试通过首先建立自己的测试夹具,从头创建所有用作输入的数据来运行,那么该测试就保证是*隔离的*。无论测试以何种顺序运行,结果都将完全相同。(这与函数式编程中的引用透明性具有相同特性。)
xUnit测试框架(至少大多数框架)通过为每个测试创建新的测试对象实例并在运行测试前执行setUp()函数来促进隔离性。(某些框架,特别是NUnit,会重用测试实例,这为破坏隔离性打开了大门。)
假设我们有一组隔离的测试并将它们一起运行。该测试套件的成功应给我们信心(按期望特性术语来说具有*可预测性*),即使每个单独的测试本身并不全面。
示例——假设我们有一个测试:
`test1() object := new Whatever() actual := object.doSomething() assertEquals(expected, actual)`
我们让这个测试通过了,现在想实现下一个功能。我们复制、粘贴并扩展:
`test2() object := new Whatever() actual := object.doSomething() assertEquals(expected, actual) actual2 := object.nowSomethingElse() assertEquals(expected2, actual2)`
我见过这样的测试被复制、粘贴并扩展了6、7次。最后一个测试非常难以阅读。
请注意,如果test1失败,test2就不可能通过。被test1捕获的所有不合规程序也将被test2捕获。我们至少有3个选项可以保持相同的覆盖率和相同的可预测性:
- 保留两个测试。
- 删除test1。
- 简化test2。
从纯粹的审美角度(不要低估审美),保留两个测试原样会违背我的直觉。它们是冗余的!*肯定*有问题。
删除test1会使我们失去测试期望特性中的另一个属性——测试应具有*特定性*。这是测试的属性,当一个测试失败时,你确切地知道问题所在。
这就引出了我偏好的解决方案——组合。我修剪test2以避免纯粹冗余的部分:
`test2() object := new Whatever() object.doSomething() actual := object.nowSomethingElse() assertEquals(expected, actual)`
test1和test2的组合没有失去任何可预测性属性。它也没有失去任何特定性属性。事实上,组合可能更具特定性,因为test1可能失败而test2通过(尽管它们可能因共同原因都失败)。
假设我们有4种计算利息的方法和5种报告利息的方法。暴力测试方法是20个测试。然而,使用组合,我们可以用10个测试实现对系统的相同信心。如果计算利息的变体与报告的变体在函数式编程意义上是分离的,那么我们需要:
- 4个计算测试
- 5个报告测试
- 1个结合计算和报告的测试,以证明它们被正确连接
从组合测试中获得信心需要一些思考、推理和设计(以使正交维度可证明为正交),但编写测试的投资会带来回报,使测试:
- 更快
- 更易读
- 更易更改
- 更具体
- 对结构变更不敏感
当我解释组合式测试的含义时,经常收到经验丰富的测试开发者的震惊反应。“我*绝不会*减少测试中的断言。”这在我看来是基于恐惧而非原则的反应。我们*如此努力*才能开始编写测试。我们不能让它们*变得更糟*。
组合并不是让测试变糟。组合是从整体角度看待测试,试图根据测试的几个有价值属性让整体变得更好。
通过CodeRabbit提升团队代码质量和交付速度——这是专为工程师打造的最先进AI代码审查工具。CodeRabbit提供上下文感知的逐行审查、即时一键修复和简洁的PR摘要,直接集成到您的GitHub工作流中,让您减少差异浏览时间,更多时间用于构建。
- CodeRabbit提供适应您团队标准的AI驱动审查,执行风格检查、发现错误和边缘情况,并自动映射代码依赖关系。
- 支持多种语言和超过40种linter及静态分析工具,无论您的技术栈多复杂,它都能保持代码整洁、安全且可维护。
- 真实案例显示显著影响:SalesRabbit通过在所有部署中添加CodeRabbit,将错误减少30%,工程速度提升25%。
- 专为初级和经验丰富的开发者设计,CodeRabbit能发现资深审查者可能遗漏的问题,其内置文档和报告让每个人保持知情和协调。
免费试用14天 (https://coderabbit.link/kent-beck)
> 加入数千名使用CodeRabbit将代码审查时间和缺陷率减半的开发者行列。开始您的14天免费试用,体验无缝AI审查、可操作反馈和轻松的代码库学习。准备好优化您的工程工作流了吗?(CodeRabbit对公共仓库免费,Pro功能面向企业团队提供——立即开始改变您的代码审查)
*由CodeRabbit赞助。*
相似文章
上下文使测试更具可重用性
作者分享了在Guile中设计测试框架的经验,重点探讨了向测试定义添加上下文如何使测试更可重用并改善开发者体验。
思考测试:断言与匹配器
本文探讨了软件开发中测试断言与匹配器的设计,强调了它们在编写可读且高效的测试代码中的作用,特别是在 Ruby 中。
@playwrightweb:Playwright 的组件测试有了新形态:stories 与 galleries。一个 story 将你的组件封装在一个场景中——props、providers、mock data……
Playwright 正在引入一种新的组件测试方式,即“stories 与 galleries”——story 在 *.story.tsx 文件中将组件封装为一个场景(props、providers、mock data),而 gallery 页面则由你自己的开发服务器提供,按需渲染各种框架中的 stories。欢迎对实验性的 CT 包提供反馈。
@kettanaito:越来越多的人向我询问测试资源,所以我把写过的所有内容汇总在一篇文章里。收藏、…
作者将一系列关于软件测试基础的文章进行了汇总,涵盖了测试的目的、断言、代码覆盖率以及处理不稳定性测试等内容。
CoSPlay:测试时基于自生成代码和单元测试的协作式自博弈
CoSPlay 是一个免训练框架,通过协作式自博弈同时提升代码生成与单元测试质量,在无需真实单元测试的情况下达到了具有竞争力的性能。