E2E 测试是什么?学 Harness 工程时第一次搞懂它
E2E 测试是什么?学 Harness 工程时第一次搞懂它
DONE.md 里有一行不起眼的 checkbox:「E2E smoke 测试通过」。我盯着它看了半天,不知道 E2E 是什么,更不知道它为什么跟编译、单元测试并列为「完成标准」。这篇文章把当时搞明白的东西从头讲一遍。
目录
- DONE.md 里的一行代码
- E2E 到底是什么
- 为什么单元测试不够
- E2E 测试家族:Smoke / Sanity / 全面 E2E
- E2E 在 Harness 工程中的位置
- 常用工具速览
- 第一个 E2E 测试长什么样
- 写在最后
DONE.md 里的一行代码
前阵子在学 Harness 工程,读到项目的完成标准文件DONE.md。这个文件的作用很简单:列一个 checklist,所有条目都打勾了,任务才算完成。
功能完成标准大概长这样:
- [ ] 编译通过(mvn clean package -DskipTests 无报错) - [ ] 单元测试通过(mvn test -pl ruoyi-business) - [ ] 新增功能有对应测试(TDD:先写测试再写实现) - [ ] 前端构建通过(npm run build:prod) - [ ] E2E smoke 测试通过(npm run test:smoke) - [ ] 涉及数据库变更的,SQL 增量脚本已更新到 sql/前几条我都认识:编译、单元测试、前端构建,都是日常在做的。但第五条「E2E smoke 测试通过」,我第一次见。
E2E 是什么?Smoke 又是什么?为什么它跟编译、单元测试并列,是完成标准的硬性要求?
查了一圈资料之后,搞明白了。这篇文章把 E2E 测试从零讲一遍,面向跟我当时一样「听过但说不清楚」的开发者。
E2E 到底是什么
E2E 是 End-to-End 的缩写,中文叫「端到端测试」。
一句话解释:站在真实用户的角度,模拟操作流程,验证整个系统从头到尾能不能跑通。
「端到端」的两个「端」分别是:
- 前端:用户看到的界面、点击的按钮、输入的表单
- 后端:服务器处理请求、查数据库、返回结果
中间经过的所有环节——前端渲染、API 调用、后端逻辑、数据库读写——E2E 测试全部走一遍。
拿一个具体的业务场景举例。用户在运维管理平台上提交一条问题记录:
用户打开问题列表页 → 点击「新增问题」按钮 → 填写问题描述、选择试验点 → 提交表单 → 前端发 POST 请求到后端 API → 后端 Service 处理业务逻辑,写入数据库 → 返回成功响应 → 前端刷新列表,新记录出现E2E 测试就是用代码模拟上面这整条链路。它不管你后端用了什么框架、前端用了什么组件库,它只关心一件事:用户操作之后,预期的结果有没有出现。
用 ASCII 画一下数据流:
┌──────────┐ HTTP ┌──────────┐ SQL ┌──────────┐ │ 用户操作 │ ─────────▶ │ 后端 API │ ─────────▶ │ 数据库 │ │ (前端) │ ◀───────── │ (Service) │ ◀───────── │ (MySQL) │ └──────────┘ 响应结果 └──────────┘ 查询结果 └──────────┘ E2E 测试验证:这条完整链路能不能跑通,结果对不对这跟单元测试不一样。单元测试只测一个零件——比如 Service 层的某个方法,输入 A 是不是返回 B。E2E 测试测的是整辆车——从用户踩油门到车子跑起来,中间每个环节都得对。
为什么单元测试不够
你可能会问:项目已经有单元测试了,为什么还要 E2E?
单元测试验证的是零件质量,E2E 验证的是整车能不能开。零件都合格,不代表装在一起能跑。
说一个我遇到过的真实场景。一个后端模块,Service 层的单元测试全绿——每个方法单独测都对。但前端调接口的时候,返回格式跟前端期望的不一致。单元测试没发现这个问题,因为它测的是 Service 内部逻辑,不涉及 API 返回格式。E2E 测试能发现,因为它走的是完整的「前端请求 → 后端处理 → 返回结果」链路。
在 AI Coding 的场景下,这个问题更突出。AI 写代码的特点是:每个零件可能都对,但组装起来容易出问题。比如 AI 给后端加了一个接口,字段名用驼峰,前端调的时候用了下划线。两边的单元测试各自通过,合在一起就报错。E2E 测试从用户视角走一遍,这种跨层的问题一眼就能看出来。
单元测试告诉你「这个方法对不对」,E2E 测试告诉你「这个功能能不能用」。
E2E 测试家族:Smoke / Sanity / 全面 E2E
E2E 不是一个单一概念,它下面分了好几种。你看到的 DONE.md 里写的是「E2Esmoke测试」,不是「E2E 测试」。这个 smoke 前缀有讲究。
| 测试类型 | 测什么 | 目的 | 什么时候跑 |
|---|---|---|---|
| E2E Smoke 测试 | 系统关键端到端流程(如登录→下单→支付) | 快速验证核心功能是否可用 | 每次代码提交、部署后,或生产环境定时监控 |
| 全面 E2E 测试 | 系统大部分或全部业务流程 | 全面验证各业务流程的功能正确性 | 测试阶段或发版前,耗时较长(10-30 分钟) |
| 冒烟测试 (Smoke Test) | 最基本、最核心的功能点 | 确保被测版本「可测」,不会让后续测试阻塞 | 新版本提交后,正式测试开始前 |
| 健全测试 (Sanity Test) | 被修改或新增的特定功能模块 | 快速验证修复或新功能是否破坏了原有功能 | 收到修复补丁或新功能后 |
这四个容易搞混,核心区别在范围和时机:
- Smoke:范围最小,跑最快,回答「系统活着吗」
- Sanity:范围稍大,回答「这次改动有没有搞坏别的」
- 全面 E2E:范围最大,回答「所有功能都正常吗」
为什么 DONE.md 里用的是 Smoke 而不是全面 E2E?因为 Smoke 是部署门禁——每次代码提交或部署后立刻跑,几分钟内出结果。如果 Smoke 都过不了,后面的全面测试不用跑了,直接打回。
Smoke 测试的两个核心场景:
场景一:部署门禁。代码部署到测试环境或生产环境后立刻跑 Smoke。通过了才允许继续;失败了直接阻断,避免浪费后续的测试资源。
场景二:生产监控。在生产环境每 5-15 分钟定时跑 Smoke。相当于 7x24 小时的自动巡检,核心功能一出问题立刻告警。
Smoke 测试的价值在于:用最小的成本,最快地拿到核心功能是否正常的反馈。不追求覆盖面,追求速度和确定性。
E2E 在 Harness 工程中的位置
回到最开始的 DONE.md。再看一遍那几条功能完成标准:
1. 编译通过 ← 代码能编译 2. 单元测试通过 ← 零件没问题 3. 新增功能有对应测试 ← TDD 保障 4. 前端构建通过 ← 前端能打包 5. E2E smoke 测试通过 ← 整车能跑这五条不是随便列的,它们有顺序:从零件到整车,从局部到整体。E2E Smoke 是最后一道闸门——前四条全过了,E2E 再验证一次完整的业务流程,全过了才算完成。
在 Harness 工程的 9 步开发流程中,E2E 测试出现在第 6 步「集成验证」:
第 5 步 TDD 实现写完代码后,第 6 步跑集成验证——编译、单元测试、E2E Smoke 一起上。全部通过才能进入第 7 步的代码审查。
这个设计的逻辑很清晰:AI 写的代码,零件级验证(单元测试)和整车级验证(E2E)缺一不可。单元测试保证每个方法对,E2E 保证整个功能能用。Harness 把这两层验证都写进了完成标准,不给 AI「只写单元测试就交差」的机会。
E2E Smoke 不是可选项,是完成标准的硬性要求。没跑过 E2E,任务就不能算完成。
常用工具速览
写 E2E 测试需要自动化工具。主流的有三个:
| 工具 | 一句话定位 | 适合场景 |
|---|---|---|
| Playwright | 微软出品,API 现代,多浏览器支持,可靠性高 | 新项目首选,适合大部分 Web 项目 |
| Cypress | 对前端框架友好,调试体验好 | React / Vue 项目,前端团队主导 |
| Selenium | 老牌工具,生态成熟,支持语言多 | 遗留项目、需要跨语言集成 |
新手推荐从 Playwright 开始。理由很简单:API 设计现代(async/await 风格),自动等待机制减少了 flaky tests(时好时坏的测试),支持 Chromium / Firefox / WebKit 三种浏览器,社区活跃文档齐全。
如果你的项目是 Vue 3 + Spring Boot(跟我学 Harness 时的项目一样),Playwright 是最省心的选择。它不关心你前端用什么框架,只管打开浏览器、模拟操作、检查结果。
第一个 E2E 测试长什么样
用一个伪代码例子展示 E2E 测试的核心结构。假设我们要测用户登录流程:
test('用户登录成功后能看到首页',async({page})=>{// 第一步:打开登录页awaitpage.goto('http://localhost:3000/login');// 第二步:填写表单awaitpage.fill('#username','admin');awaitpage.fill('#password','123456');// 第三步:点击登录按钮awaitpage.click('#login-btn');// 第四步:断言结果awaitexpect(page).toHaveURL('/dashboard');awaitexpect(page.locator('.welcome-msg')).toContainText('欢迎');});四个步骤对应 E2E 测试的核心要素:
| 步骤 | 作用 | 对应操作 |
|---|---|---|
| 打开页面 | 进入测试起点 | page.goto() |
| 模拟操作 | 填表单、点按钮 | page.fill()/page.click() |
| 等待响应 | 系统处理请求 | Playwright 自动处理 |
| 断言结果 | 验证预期是否达成 | expect() |
注意看这段测试代码——它写的是用户行为,不是代码实现。它不知道后端用了 Spring Boot 还是 Express,不知道数据库是 MySQL 还是 PostgreSQL,不知道登录逻辑用了 JWT 还是 Session。它只知道:输入用户名密码、点登录、应该跳转到首页。
这就是 E2E 测试的特点:从用户视角出发,验证的是业务结果,不关心技术实现。如果哪天后端换了框架,只要用户操作流程和结果不变,E2E 测试不需要改。
写在最后
回到最开始那个问题:DONE.md 里的「E2E smoke 测试通过」到底是什么意思?
现在清楚了:它是端到端冒烟测试,站在用户角度走一遍核心业务流程,验证系统整体能不能正常工作。它不追求覆盖面,追求的是速度——几分钟内告诉你核心功能是否「活着」。
在 Harness 工程的完成标准里,E2E Smoke 是最后一道闸门。编译通过、单元测试通过、前端构建通过之后,E2E Smoke 再验证一次完整的业务链路。全过了,任务才算完成。
如果你也在用 AI Coding 做业务项目,建议把 E2E Smoke 加到你的完成标准里。不需要一开始就写很多,先覆盖最核心的一两条流程就行。比如用户登录、创建一条记录、查看详情——这三个场景跑通了,系统基本不会出大问题。
工具选 Playwright,上手快,文档好,跑起来省心。
E2E 测试的价值就一句话:用最小的成本,最快地告诉你系统核心功能是否正常。