主题
界面
主题
《UI 测试稳定性与失败重试边界》解决了"稳定性";本节解决UI 测试最现实的约束:
22 个用例 → 168 秒(串行) ← 还能忍
500 个用例 → 63 分钟 ← 没人等了 ✗✗UI 测试太慢,而"慢"会直接导致"没人跑" ✓ ——所以提速是必答题 ✓
本节讲三个手段,其中只有一个真正常用 ✓✓:
| 手段 | 效果 | 代价 |
|---|---|---|
| ① 少测一点(冒烟集)★★★ | 最有效 ✓ | 需要判断"哪些最该测" ✓ |
| ② 并行 ★★ | 取决于机器 ⚠️ | 成倍占用资源 ✗(本节实测:本机反而更慢) |
| ③ 用接口准备数据 ★★★ | 大幅减少 UI 操作 ✓ | 需要接口测试能力 ✓ |
先看一个"UI 测试被放弃"的典型过程 ✗:
第 1 周:20 个 UI 用例,跑 3 分钟 → 每次提交都跑 ✓
第 4 周:80 个用例,跑 12 分钟 → 改成每晚跑一次 ⚠️
第 8 周:200 个用例,跑 30 分钟 → 每晚跑不完,改成每周 ⚠️
第 12 周:没人记得它还在跑 ✗✗★ 关键数字在哪 ✓:
超过 10 分钟,人就不愿意等了 ✓(T2-004 5.6①)✓
所以 UI 测试的用例数必须有"预算" ✓✓
本项目的量级感受:
22 个 UI 用例 → 168 秒(串行) ← 单类测试尚可,全量提交前跑一次可接受核心思想:不是"跑得快点",而是"少跑一点" ✓✓
★ 冒烟集怎么选(四条判据):
| # | 判据 | 例子 |
|---|---|---|
| ① 覆盖关键用户路径 ★★★ | 能走通的"主流程" | 打开页面 → 创建 → 列表可见 → 删除 ✓ |
| ② 每个模块最多 1~2 条 ★★ | 不全覆盖,只"探活" | 订单模块 2 条,不做边界 |
| ③ 快 ★★ | 单条 < 30 秒 | 不做多步流程 ✓ |
| ④ 稳定 ★★★ | 不能有 flaky | 有 flaky 的先修或隔离 |
★ 一句话概括冒烟集:
它回答"系统是不是基本能用",不回答"功能是否完全正确" ✓✓
后者的任务是回归测试(可以慢、可以低频) ✓
本项目的冒烟集(UiSmokeTest,@Tag("smoke"))✓:
| 用例 | 覆盖 |
|---|---|
smoke_01_home_page_loads | 页面能打开、标题对 ✓ |
smoke_02_async_panel_loads | 异步区块能加载(等待正确)✓ |
smoke_03_list_renders_rows | 列表能渲染数据 ✓ |
smoke_04_create_appends_row | 创建后能看到新行 ✓ |
smoke_05_delete_removes_row | 删除后行消失 ✓ |
non_smoke_secondary_path | 不进冒烟集(次要路径)✓ |
实测规模:
Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 36.66 s
--- in cn.kb.learn.ui.UiSmokeTest★ 六个用例 36.66 秒 = 平均 6.1 秒/条 ✓ ——符合"每条 < 30 秒"的标准 ✓
★ 用一个标签就把"冒烟"与"全量"分开了 ✓:
@Tag("ui")
@Tag("smoke")
class UiSmokeTest { ... }pwsh -File scripts\ui-test.ps1 -Smoke # 只跑冒烟集
pwsh -File scripts\ui-test.ps1 # 跑全部 UI并行的前提:用例之间必须彼此独立 ✓✓
| 前提 | 不满足的后果 |
|---|---|
| 不共享数据 ★★★ | 互相改对方的列表 → 断言失败 ✗(T2-011 的真实案例) |
| 不共享浏览器实例 ★★ | 操作互相干扰 ✗ |
| 不依赖执行顺序 ★★★ | 顺序一变就失败 ✗ |
| 不抢同一份外部资源 ⚠️ | 比如同一个测试账号、同一个库存 ✗ |
★ 配置方式(JUnit 5,本项目已配好)✓:
# junit-platform.properties
junit.jupiter.execution.parallel.enabled=false # 默认关:并行不是免费的
junit.jupiter.execution.parallel.mode.default=same_thread
junit.jupiter.execution.parallel.mode.classes.default=concurrent
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.config.fixed.parallelism=4pwsh -File scripts\ui-test.ps1 -Parallel # 4 线程
pwsh -File scripts\ui-test.ps1 -Parallel -Parallelism 2 # 指定线程数★★★ 本轮的实测:并行反而更慢 ✓✓✓
| 串行 | 并行(4 线程) | |
|---|---|---|
| 用例数 | 22 | 22 |
| 总耗时 | 167.96 s | 302.35 s ✗✗ |
| 驱动实例 | 1 个 | 4 个 |
msedge 进程峰值 | 约 8 个 | 17~24 个 ⚠️ |
| 各测试类耗时 | 50.58 / 29.70 / 21.42 / 36.66 / 29.60 s | 76.27 / 52.49 / 42.46 / 72.39 / 58.74 s |
★ 每个测试类都变慢了 30%~70% ✓ ——总时间增加了 80% ✗✗
原因:
4 个浏览器实例在同一台机器上争抢 CPU 与内存 ✓
这与 T2-003 的"同机压测"是同一个道理 ——资源不是无限的 ✓✓
★ 附带发现:并行的报告会"归类错乱" ✓✓✓
串行报告:
OrderLocatorTest 5 个 ← 实际就是 5 个 ✓
UiEnvironmentCheckTest 3 个 ← 实际就是 3 个 ✓
并行报告:
OrderLocatorTest 1 个 ✗ 归属错了
UiEnvironmentCheckTest 10 个 ✗ 归属错了
(总数仍是 22 ✓)为什么:并行执行时,测试事件的"归属类"是按"完成的线程上下文"记录的 ✗ —— 于是"5 个"被算到了别的类头上 ✓
★ 这个发现很实用:
并行会让"按类统计"的报告失真 ✓ —— 排查"哪个类挂了"时不要只看报告的分类数字 ✓✓
这也是"报告要能自证"的又一例(T2-017 5.2)✓
★★ 那到底该不该开并行 ✓:
| 情况 | 建议 |
|---|---|
| 单机、资源一般(本项目的位置) | 不开 ✗ ——开了更慢 ✓ |
| 多核大内存的 CI 机器 | 开,但要先实测 ✓ |
| 用例之间不独立 | 先修隔离,再谈并行 ✗✗ |
| 任何情况 | 先测再开,不要假设"并行=更快" ✓✓ |
这是"提速"里最容易被忽略、但收益最大的一招 ✓✓
问题:很多 UI 用例的前置步骤是"造数据" ✗ ——而造数据本来就不需要经过界面 ✗✗
对比:
// ✗ 用 UI 造数据:每次创建要走"打开页面 → 填表 → 提交 → 等跳转"
for (int i = 0; i < 5; i++) {
page.createOrder("商品" + i, "1", "地址" + i); // 每次约 6 秒 → 30 秒 ✗
}
// ✓ 用接口造数据:一次 HTTP 请求
for (int i = 0; i < 5; i++) {
given().contentType(JSON)
.body("{\"productId\":\"P-" + i + "\",\"quantity\":1,\"address\":\"地址\"}")
.when().post("/api/orders"); // 每次约 0.1 秒 → 0.5 秒 ✓✓
}★ 提速约 60 倍 ✓ ——而且不碰界面,也就不会因界面变化而失效 ✓✓
★ 这个做法的原则:
UI 测试只该验证"界面能否呈现",不该负责"把数据准备好" ✓✓
数据准备交给接口(T2-005),UI 只做"看一眼" ✓
★ 本项目已经在用这个思路 ✓:
UiPageController 构造时创建的(相当于夹具)✓UI 测试不能"每次提交都全量跑" ✗ ——所以要给它排班 ✓:
| 时机 | 跑什么 | 预期时长 |
|---|---|---|
| 每次提交(PR) ★ | 冒烟集 ✓ | < 1 分钟 |
| 合并到主干 ★ | 全量 UI ✓ | 3~10 分钟 |
| 每晚 ★★ | 全量 UI + 跨浏览器(如需) | 30 分钟+ |
★ 这与 T2-004 的分层思路完全一致 ✓:
能快的地方快,该慢的地方慢慢跑 —— 关键是"让快的先给结论" ✓✓
★ 本项目现在的流水线还没有 UI 层 ✗ ——因为 UI 需要额外的环境准备(启动应用) ✓ 这也是 scripts/ui-test.ps1 单独存在的原因 ✓✓
@Tag("smoke")
@Test
void smoke_01_home_page_loads() { ... }scripts\ui-test.ps1 -Smoke # 冒烟:约 37 秒
scripts\ui-test.ps1 # 全量:约 168 秒
scripts\ui-test.ps1 -Parallel # 并行:约 302 秒(本机反而更慢)✗junit.jupiter.execution.parallel.enabled=true // ✗ 没实测过就开测试代码:
labs/ui-testing/src/test/java/cn/kb/learn/ui/UiSmokeTest.java(冒烟集,@Tag("smoke"))labs/ui-testing/src/test/resources/junit-platform.properties(并行配置)入口:scripts/ui-test.ps1(支持 -Smoke / -Parallel / -Parallelism)
★ 实测一:串行全量 ✓
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 50.58 s -- OrderLocatorTest
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 29.70 s -- OrderPageObjectTest
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 21.42 s -- UiEnvironmentCheckTest
Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 36.66 s -- UiSmokeTest
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 29.60 s -- UiStabilityTest
合计:22 个用例,167.96 秒(约 2.8 分钟)★ 实测二:并行(4 线程) ✗
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 76.27 s -- OrderLocatorTest
Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 52.49 s -- OrderPageObjectTest
Tests run: 10, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 42.46 s -- UiEnvironmentCheckTest
Tests run: 4, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 72.39 s -- UiSmokeTest
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 58.74 s -- UiStabilityTest
合计:22 个用例,302.35 秒(约 5 分钟)★★ 三个可以直接写进报告的结论 ✓:
| # | 结论 | 依据 |
|---|---|---|
| ① | 本机上并行让 UI 测试慢了 80% | 167.96 s → 302.35 s ✗ |
| ② | 并行的代价是"成倍的浏览器进程" | 1 个驱动 → 4 个驱动;8 个 msedge → 17~24 个 ⚠️ |
| ③ | 并行的报告"按类统计"会失真 | OrderLocatorTest 从 5 变 1、UiEnvironmentCheckTest 从 3 变 10 ✗(总数仍 22 ✓) |
★ 实测三:冒烟集单独跑 ✓
Tests run: 6, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 36.66 s冒烟集 36.66 秒 vs 全量 167.96 秒 ✓ ——只跑 27% 的用例,用了 22% 的时间 ✓✓
★ 这才是"提速"的正解:
不是"更快地跑全部",而是"只跑最有价值的那部分" ✓✓
msedge 进程数(本机到过 24 个)★★;-Parallelism 2 再跑一次:观察是否比 4 线程更快(提示:可能更快,因为争抢变少)★;| # | 错误 | 说明 |
|---|---|---|
| 1 | 以为"并行 = 更快" ✗✗ | 本轮实测反例:慢了 80% ✗✗ |
| 2 | 用例不独立就开并行 ✗✗ | 随机失败(T2-011)✗✗ |
| 3 | 冒烟集选得太多 ✗ | 从 37 秒变 3 分钟,就没人跑了 ✗ |
| 4 | 冒烟集里放 flaky 用例 ✗✗ | 每次都红,团队学会忽略 ✗✗ |
| 5 | 用 UI 造数据 ✗✗ | 慢 60 倍(5.3)✗✗ |
| 6 | 看并行的"按类统计"排查问题 ⚠️ | 归属失真(5.2)✗ |
| 7 | 每次提交都跑全量 UI ✗ | 拖垮反馈速度(5.4)✗ |
目标:亲手测出"并行到底更快还是更慢"。
步骤:
msedge 进程数,与串行对比 ★;-Parallelism 2 再跑一次,看是否比 4 线程更优 ★★;验收方式:能说出"你这台机器上,并行比串行快还是慢、为什么"。
扩展任务:找出"最适合本机的并行度":
@Tag("smoke"),然后让 PR 流水线跑冒烟集。有什么问题?ui-test.ps1 加一个 -Jobs <n> 参数,自动跑多个并行度并输出耗时对比表(便于找出本机最佳并行度)。UI 自动化五节(T2-002 / T2-009 / T2-010 / T2-011 / T2-012)到此完成。
TB 模块剩余:
之后回到主线的 S2 / S4 / S5 等阶段(见 matrix.md)。
暂无