持续测试:质量不是一道关,是流水线的属性
持续测试:质量不是一道关,是流水线的属性
1. 这一章讲什么
开篇用四个真实事故立论:YouTube 播放量计数器 32 位溢出(「江南 Style」冲破约 21 亿次)、新泽西医院系统重复发出数千个疫苗预约、英国邮局 Horizon 系统 bug 冤枉数百名支局长十多年、法国财政部给 20 万公务员多发一遍工资1——软件 bug 不是技术细节,是公共事件。然后回答:在 DevOps 里,测试如何从「开发完后的一道关」变成「嵌在流水线每个阶段的连续活动」。
2. 顶层全景
概念三层: 手动测试(人按步骤) → 自动化测试(脚本自动跑) → 持续测试(嵌进 CI/CD,自动跑+自动反馈)
测试二分: 功能测试(做对没有) | 非功能测试(做得多好:快不快、稳不稳、安不安全)
位置二分: shift-left(尽可能早) + shift-right(上线后还在测)主线例子(本章共用的演示):一个 calculate_total 函数的单测,从 unittest 写法到 pytest 写法,最后跑进 GitLab CI 流水线。
3. 核心原理
3.1 自动化测试 ≠ 持续测试
这是本章最关键的概念切割。书里用一问一答点破2:
光有自动化测试,在 DevOps 里够吗?——不够。
自动化测试只回答「测试跑了吗、过了吗」;它不回答什么时候跑、跑得多勤、结果推给谁、是否跟得上持续交付的节奏——这些正是持续测试补上的部分:测试在流水线的每个阶段被自动触发,结果实时推给开发/QA/运维,渠道是 Slack、邮件、看板、Jira,而不是躺在某个日志文件里3。
3.2 持续测试在流水线里怎么走一遍
书里把过程画成一条链4:开发者推代码 → CI 触发 → 第一步是代码质量分析(SonarQube、ESLint 扫安全漏洞和坏味道)→ 构建(编译错立刻反馈)→ 部署到类生产测试环境 → 跑单测/集成/UI 测试 → 结果上仪表板通知相关人 → 全绿继续往下走或暂停等人工批准。测试环境要尽量「仿真生产」,否则测出来的结论不可靠4。
3.3 测试类型地图
功能测试(做对没有)六种,记前四种就够5:
| 类型 | 测什么 | 类比(书里造车比喻) |
|---|---|---|
| 单元测试 | 单个函数/方法 | 先单独测车灯、刹车、发动机 |
| 集成测试 | 模块间的协作 | 装上车后踩刹车,车真的减速吗 |
| 回归测试 | 改动有没有弄坏原来好的功能 | 修完登录 bug 要重查密码重置 |
| 系统测试 | 整机端到端 | 整车在真实路况跑 |
集成测试的三种路线值得一提:大爆炸(全装完再测,出错难定位)、自顶向下(用桩 stub 模拟下层)、自底向上(用驱动 driver 模拟上层)、三明治(两头并进)6。**UAT(用户验收测试)**是功能测试的终点:由真实用户/客户在类生产环境验证「这软件在现实世界里干的是不是我要的事」——目标是验收不是抓虫7。
非功能测试(做得多好):速度/扩展性/负载三兄弟(负载=特定压力下表现,扩展性=随负载增长的表现8)、无障碍(WCAG/ADA 合规)、兼容性、可靠性与灾难恢复、合规(GDPR/HIPAA/PCI-DSS)与本地化9。
另有两把按「可见度」分的尺子:黑盒(不知内部,只看输入输出)、白盒(看着代码设计用例)、灰盒(知道一半,如数据库 schema);和按「时机」分的三档:alpha(内部测)、beta(放给一批真实用户)、pilot(在真实环境小范围试点后推广)10。
3.4 主线例子:一个函数的三次投胎
第一世,unittest 写法(Python 标准库,类继承 unittest.TestCase,断言 assertEqual)11:
class TestMathOperations(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)第二世,pytest 写法——不用类、不用继承,函数名以 test_ 开头,普通 assert 就行;pytest 命令自动发现所有 test_*.py 文件,-v 给详细失败报告12:
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0第三世,进流水线。.gitlab-ci.yml 里一个 test 阶段:用 python:3.8 镜像 → before_script 装依赖 → script: pytest --maxfail=1 --disable-warnings -q → 报告存 artifacts(连失败也存,when: always)→ only: [master] 只在主分支触发13。进阶版:专门做一个测试镜像(DockerfilePyTest:装好 pytest 和 pandas,CMD pytest --junitxml=./report/test_report.xml),CI 里 build → run → 把 XML 报告作为 artifact 回传 GitLab——七步:commit → runner 克隆 → build 镜像 → 起容器 → 容器里跑 pytest → 报告存 artifact → 人在 GitLab 界面看报告14。
3.5 覆盖率:有用,但别供着
代码覆盖率 = 测试运行时实际执行到的代码百分比,分子分母有四类量法:函数覆盖、语句覆盖、分支覆盖(每个 if/else 两条路都走过没有)、条件覆盖15。书里的清洁房屋类比:只扫了客厅,「清洁覆盖率」就低15。Python 工具链:coverage run -m pytest 跑测试并记账,coverage report 出表,coverage html 出可视化页面——书里的样例是 55% 总覆盖,某文件 46 句跑了、漏 48 句、覆盖 49%16。
**100% 覆盖要不要追?书里的答案:谨慎。**全覆盖可能逼你为琐碎代码写无意义测试,还可能给你虚假安全感——为关键模块和复杂逻辑写高质量测试,比追数字重要17。
代码质量(coverage 的姊妹概念)是静态度量,不看跑没跑:长函数、深嵌套、参数过多、重复代码都是坏味道;工具 Code Climate 可接进 GitLab CI,报告以 Code Climate JSON 格式给 GitLab 解析,在合并请求里直接出注释18。
3.6 Shift-left + Shift-right,规模化的四件事
左移:测试尽可能靠近写代码的那一刻——开发者边写边写单测,小步快跑,bug 越早抓越便宜19。右移:上线后还在测——真实环境、真实流量下的表现和体验,比如用金丝雀发布观察线上指标19。书里的立场:两个都要,不是二选一。
规模化测试靠四招20:重度自动化(各阶段自动触发)、并行化(Jenkins/Selenium Grid/云 runner 多机同跑)、可伸缩基建(容器按需起测试环境)、聪明筛选(冒烟测试先跑一遍拦大坑,再全量回归;测试影响分析只跑受影响的用例)。外加测试数据治理。
最佳实践四条21:覆盖率当指路牌不当 KPI;处理测试债、慢测试、flaky test(随机成败的测试最毁人对流水线的信任——要定期修或删);把测试当一等公民随功能一起维护;AI 预测 flaky 测试、生成合成测试数据、按风险排用例优先级。
4. 作者的判断与证据
有出处的:四个事故均有新闻来源脚注1;unittest/pytest/覆盖率命令是可直接复现的演示。
作者的判断:「自动化测试不够,要持续测试」是本节真正的论点2,论证方式是列出维度对照表(范围/触发点/反馈环/治理等 13 行),有说服力。100% 覆盖的保留态度是业界主流意见,书里与之一致。
我们的补充:「shift-left/right」的术语来自 2010 年代中期的测试社区(书里用了词没给出来历);「测试金字塔」(单测多、E2E 少)是相关的主流框架,本章未提(补充,不在书里)。
5. 边界与局限
- 微服务下的端到端测试、契约测试(contract testing)只在复习题出现22,正文没讲——这是大规模微服务测试的真正难点。
- 性能测试只有概念和例子(JMeter 出现在工具清单),没有实操。
- AI 测试一段是方向性描述,无工具实证。
- 安全测试(OWASP ZAP 等)只在阶段图里露名。
6. 可带走的
- 自动化测试只保证「脚本会跑」;持续测试保证「每个阶段都在跑、结果实时到人」23。
- 流水线里测试的触发顺序:质量扫描 → 构建 → 类生产环境部署 → 单测/集成/UI → 报告通知4。
- 功能 vs 非功能:做对没有 vs 做得多好(快、稳、安全、合规)9。
- 集成测试四路线:大爆炸 / 自顶向下(stub)/ 自底向上(driver)/ 三明治6。
- pytest 三句话上手:
test_开头自动发现、裸assert、-v看详情12。 - GitLab CI 里测试落地:镜像 + before_script 装依赖 + script 跑 pytest + artifacts 存报告(
when: always)13。 - 覆盖率四量:函数/语句/分支/条件;100% 覆盖可能是虚假安全感1517。
- 左移(早测)+ 右移(上线后测)不是二选一19。
- flaky test 是流水线信任的头号杀手,定期清理21。
7. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| 四个软件事故开篇 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:17(搜「32-bit counter」) · text/14-ch09-9-continuous-testing.txt:24(搜「Post Office」) |
| bug 来源清单 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:73(搜「Race conditions」) |
| 自动化测试不够 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:200(搜「Is automated testing alone sufficient」) |
| 持续测试 vs 自动化对照 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:224(搜「Continuous execution of tests」) |
| 流水线中的测试流程 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:215(搜「code quality analysis」) |
| 单元/集成测试与造车类比 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:326(搜「building a car」) |
| 集成测试四路线 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:370(搜「Big Bang approach」) |
| UAT 定位 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:408(搜「final phase of functional testing」) |
| 负载 vs 扩展性 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:445(搜「major difference between load testing」) |
| 黑/白/灰盒 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:505(搜「of its internal code or logic」) |
| Selenium vs Cypress | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:551(搜「Selenium WebDriver」) · text/14-ch09-9-continuous-testing.txt:562(搜「runs directly inside the browser」) |
| 测试环境对照表 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:589(搜「Comparison of different testing environments」) |
| 数据匿名化与合成数据 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:626(搜「Anonymization」) |
| unittest 示例 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:669(搜「TestMathOperations」) |
| pytest 示例与自动发现 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:708(搜「def test_add」) · text/14-ch09-9-continuous-testing.txt:722(搜「discovers tests」) |
| pytest 进 GitLab CI | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:741(搜「job_test」) |
| 容器化测试七步流 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:801(搜「test_report_using_pytest」) |
| 覆盖率定义与四量 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:839(搜「percentage of your code」) |
| 100% 覆盖之辩 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:851(搜「100% code coverage」) |
| 代码质量与 Code Climate | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:873(搜「how clean, maintainable」) |
| shift-left / shift-right | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:923(搜「as early as possible」) |
| 规模化与最佳实践 | 9 - Continuous testing | text/14-ch09-9-continuous-testing.txt:935(搜「Testing at a small scale」) · text/14-ch09-9-continuous-testing.txt:959(搜「flaky tests」) |
Footnotes
-
出处:「9 - Continuous testing」第 16–38 段(
text/14-ch09-9-continuous-testing.txt:17,搜「32-bit counter」;:29搜「200,000 civil servants」)。 ↩ ↩2 -
出处:「9 - Continuous testing」第 199–206 段(
text/14-ch09-9-continuous-testing.txt:200,搜「Is automated testing alone sufficient」)。 ↩ ↩2 ↩3 -
出处:「9 - Continuous testing」表 9.3(
text/14-ch09-9-continuous-testing.txt:224,搜「Continuous execution of tests」)。 ↩ ↩2 -
出处:「9 - Continuous testing」第 209–267 段(
text/14-ch09-9-continuous-testing.txt:215,搜「SonarQube」)。 ↩ ↩2 ↩3 -
出处:「9 - Continuous testing」第 316–418 段(单测
:324搜「test-driven development」;系统测试:393搜「entire software system」)。 ↩ -
出处:「9 - Continuous testing」第 370–377 段(
text/14-ch09-9-continuous-testing.txt:370,搜「Big Bang approach」)。 ↩ ↩2 -
出处:「9 - Continuous testing」第 407–417 段(
text/14-ch09-9-continuous-testing.txt:410,搜「not to find bugs」)。 ↩ -
出处:「9 - Continuous testing」第 432–447 段(
text/14-ch09-9-continuous-testing.txt:445,搜「major difference between load testing」)。 ↩ -
出处:「9 - Continuous testing」第 419–494 段(咖啡机类比
:423;合规:487搜「HIPAA」)。 ↩ ↩2 -
出处:「9 - Continuous testing」第 503–540 段(alpha
:527;beta:532;pilot:536)。 ↩ -
出处:「9 - Continuous testing」第 658–690 段(
text/14-ch09-9-continuous-testing.txt:669,搜「TestMathOperations」)。 ↩ -
出处:「9 - Continuous testing」第 692–728 段(
text/14-ch09-9-continuous-testing.txt:708,搜「def test_add」;:722搜「discovers tests」)。 ↩ ↩2 -
出处:「9 - Continuous testing」第 730–768 段(
text/14-ch09-9-continuous-testing.txt:741,搜「job_test」)。 ↩ ↩2 -
出处:「9 - Continuous testing」第 770–835 段(
text/14-ch09-9-continuous-testing.txt:785,搜「junitxml」;:826搜「clones the GitLab repository」)。 ↩ -
出处:「9 - Continuous testing」第 838–859 段(
text/14-ch09-9-continuous-testing.txt:839,搜「percentage of your code」;:846搜「Branch coverage」)。 ↩ ↩2 ↩3 -
出处:「9 - Continuous testing」第 860–870 段(
text/14-ch09-9-continuous-testing.txt:864,搜「total coverage」)。 ↩ -
出处:「9 - Continuous testing」第 851–856 段(
text/14-ch09-9-continuous-testing.txt:852,搜「100% code coverage」)。 ↩ ↩2 -
出处:「9 - Continuous testing」第 872–909 段(
text/14-ch09-9-continuous-testing.txt:881,搜「Code Climate」)。 ↩ -
出处:「9 - Continuous testing」第 919–932 段(
text/14-ch09-9-continuous-testing.txt:923,搜「developers write unit tests while」;:931搜「using both strategies together」)。 ↩ ↩2 ↩3 -
出处:「9 - Continuous testing」第 934–946 段(
text/14-ch09-9-continuous-testing.txt:940,搜「heavy automation」)。 ↩ -
出处:「9 - Continuous testing」第 948–979 段(
text/14-ch09-9-continuous-testing.txt:961,搜「flaky tests」)。 ↩ ↩2 -
出处:「9 - Continuous testing」复习题(
text/14-ch09-9-continuous-testing.txt:1019,搜「microservices architecture」)。 ↩