【总结整理】软件测试的反模式

最近看到一篇介绍软件测试相关的文章,文章虽然比较早(2018年的),但是其中的观点依然适用。

在目前AI盛行的时候,软件测试也必然迎来它的变化。

我把文章中的要点整理了一下,这些测试的反模式涵盖了从测试策略、代码质量到心态管理的各个方面。

原文的链接放在了文章的末尾。

1. 只有单元测试,没有集成测试 (Having unit tests without integration tests)

  • 问题:即使所有独立的类/方法都通过了测试,但在实际运行时,组件之间的连接(数据库、网络、外部API)可能会失败。
  • 盲点:单元测试无法覆盖跨切面关注点(Cross-cutting concerns),如事务处理、SQL触发器、API契约不匹配等。
  • 建议:除非是完全隔离的工具(如命令行计算器),否则必须引入集成测试来验证系统各部分的协作。

2. 只有集成测试,没有单元测试 (Having integration tests without unit tests)

  • 问题:通常由认为"单元测试没用"的开发者造成。
  • 代价
    • 复杂度爆炸:要覆盖所有代码路径的组合,集成测试的数量会呈指数级增长,难以维护。
    • 执行极慢:反馈循环太长(从几秒变为几分钟甚至更久),降低开发效率。
    • 调试困难:测试失败时,难以快速定位是哪个组件出了问题。
  • 建议:遵循测试金字塔,用大量单元测试覆盖业务逻辑,用少量集成测试覆盖组件交互。

3. 只有错误类型的测试 (Having the wrong kind of tests)

  • 问题:盲目照搬"测试金字塔",而不考虑应用的实际类型。
  • 场景区分
    • 计算型工具(如Linux命令):应以单元测试为主。
    • 支付网关(重外部交互):应以集成测试为主。
    • 网站生成器(重交互体验):应以UI测试为主。
  • 要点:根据业务价值决定测试类型,而不是死守一种形状。

4. 测试错误的功能 (Testing the wrong functionality)

  • 问题:为了追求覆盖率而测试无关紧要的代码(如简单的 Getter/Setter),却忽视了核心风险。
  • 策略 :建立"代码严重性"心理模型:
    • 关键代码 (Critical) :经常变更、经常出错、业务影响大 -> 必须覆盖
    • 核心代码 (Core):偶尔变更 -> 尽量覆盖。
    • 其他代码 (Other):几乎不变 -> 没必要浪费时间。
  • 建议:优先覆盖那 20% 导致 80% 问题的关键代码。

5. 测试内部实现细节 (Testing internal implementation)

  • 问题 :测试与代码的实现方式 紧密耦合,而不是验证行为
  • 后果:重构代码(Refactoring)时,即使业务逻辑没变,测试也会报错。这会导致开发者认为"测试是累赘"。
  • 建议:测试应该关注输入和输出(行为),而非对象内部的状态或私有字段。

6. 过度关注代码覆盖率 (Paying excessive attention to test coverage)

  • 问题:将覆盖率(如 100%)视为唯一的质量指标,导致出现大量为了刷数据的低质量测试。
  • 观点:覆盖率只是一个参考数字。高覆盖率不代表无 Bug。
  • 更好的指标
    • PDWT:写测试的开发人员百分比(应为100%)。
    • PBCNT:生产环境 Bug 转化为新测试的百分比。
    • PTD:确定性(非不稳定)测试的百分比。

7. 拥有不稳定或缓慢的测试 (Having flaky or slow tests)

  • 问题:测试时过时挂(Flaky),导致团队失去信任,忽略测试结果。
  • 来源:通常是集成测试或 UI 测试,源于环境不稳或异步处理不当。
  • 建议:必须修复或隔离不稳定测试。测试套件必须是绝对可靠(Deterministic)的,任何失败都应代表真实的代码问题。

8. 手动运行测试 (Running tests manually)

  • 问题:依赖人工触发测试或人工准备环境,无法实现真正的 CI/CD。
  • 目标:所有与代码正确性相关的测试(单元/集成)必须完全自动化。
  • 标准:开发者提交代码后,应在 5-15 分钟内自动获得反馈。QA 应专注于设计新测试,而不是充当"测试运行器"。

9. 将测试代码视为二等公民 (Treating test code as a second class citizen)

  • 问题:生产代码写得很漂亮,测试代码却充满了复制粘贴、硬编码和糟糕的设计。
  • 后果:测试代码难以维护,修改成本高昂,最终被抛弃。
  • 建议:对测试代码应用同样的工程标准(DRY, KISS, SOLID)。重构测试代码,提取公共库及 Helper 方法。

10. 不将生产环境 Bug 转化为测试 (Not converting production bugs to tests)

  • 问题:修复了 Bug 但未添加回归测试,导致同样的问题在未来重复出现。
  • 价值:源自生产环境的 Bug 测试价值极高,因为它们直接对应了真实世界的痛点和高风险区域。
  • 规则:每一个线上 Bug 的修复,都必须伴随一个能复现该 Bug 的测试用例。

11. 将 TDD 奉为宗教 (Treating TDD as a religion)

  • 问题:教条式地要求所有代码都必须"先写测试再写实现"。
  • 现实:在探索性编程(Spike)、原型设计或极早期初创阶段,后补测试或不写测试也是合理的策略。
  • 建议:TDD 是一个好工具,但不是唯一的真理。根据项目阶段和需求清晰度灵活选择。

12. 写测试不看文档 (Writing tests without reading documentation first)

  • 问题:因为不熟悉测试框架,自己造轮子写各种笨拙的"工具方法"。
  • 后果:测试代码晦涩难懂,非标准化的写法增加了新人的学习成本。
  • 建议:深入学习测试框架的功能(如参数化测试、Mock 工具、Setup/Teardown 机制),使用标准库而非自制土方。

13. 因无知而败坏测试的名声 (Giving testing a bad reputation out of ignorance)

  • 问题:开发者因为经历过上述反模式(如经历过极慢的测试、脆弱的测试),从而彻底否定测试的价值。
  • 观点:不要因为错误的测试方式(Bad Habits)而否定测试本身。
  • 建议:识别并承认过去糟糕的测试体验是由于"反模式"造成的,在新项目中采用正确的实践。

原文章来源:Software Testing Anti-patterns

相关推荐
大话性能3 小时前
Python多线程总结
测试
Apifox1 天前
Apifox CLI + Claude Skills:将接口自动化测试融入研发工作流
前端·后端·测试
l***21781 天前
Spring Boot 整合 log4j2 日志配置教程
spring boot·单元测试·log4j
阿蔹1 天前
接口测试用例的设计方法
功能测试·接口测试·测试
Lucifer__hell1 天前
【Pytest】笔记
笔记·pytest·测试
阿蔹2 天前
Session与Cookies
selenium·测试
川石课堂软件测试2 天前
Android和iOS APP平台测试的区别
android·数据库·ios·oracle·单元测试·测试用例·cocoa
大熊猫侯佩2 天前
Swift 6.2 列传(第十七篇):钟灵的“雷电蟒”与测试附件
单元测试·swift·apple
brave and determined2 天前
工程设计类学习(DAY5):揭秘HALT试验:产品极限测试全解析
测试·hass·产品设计·halt·高低温循环·产品寿命实验·产品质量