AUTOMATION TEST · UI/接口 / CI 集成
自动化测试速查
从分层投入与工具选型,到 Web UI 定位与等待策略、接口用例分层与断言设计,再到 App 自动化、CI 流水线集成与 flaky 用例治理,自动化测试方向的 44 条高频要点一张表收齐,随查随用。
44条速查
8大主题
∞持续更新
📖 速查表
点击展开各小节
🧭 分层与选型
| 层级 / 工具 | 说明 | 选型要点 |
|---|---|---|
| 投入比 · 测试金字塔 | 单元 > 接口 > UI 的金字塔投入结构:越往下越快、越稳、越便宜,接口层是性价比最高的一层 | UI 只覆盖核心链路 重心下移 |
| Selenium | 老牌 Web UI 标准:浏览器兼容面广、生态与资料最全;需自管驱动,无原生自动等待 | 存量项目与老旧浏览器兼容场景 生态最全 |
| Playwright | 新一代 Web UI 框架:自动等待、多浏览器一套 API、原生录制与 trace 调试 | 新项目首选 现代能力全 |
| Cypress | 运行在浏览器内部,执行与调试体验好;但同源限制、多标签页 / 多域支持弱 | 前端团队内自测友好 局限也明显 |
| Requests / RestAssured | Python / Java 生态的接口自动化事实标准,配合断言库构建接口回归集 | 接口层主力 |
| Appium | 移动端自动化统一协议层:一套 WebDriver API 驱动 Android 与 iOS | 跨平台移动测试首选 |
| pytest / JUnit | 测试框架基座:pytest 以 fixture 机制与插件生态见长,JUnit 5 是 Java 生态标配 | 先定框架再写用例 |
🎭 Web UI 自动化
UI 自动化最贵的两件事是定位与等待:定位抗重构、等待不硬等,用例就稳了大半。
| 主题 | 说明 | 要点 |
|---|---|---|
| Playwright vs Selenium | 核心差异:自动等待 vs 手写等待;原生 trace / 录制 / 网络拦截 vs 依赖第三方插件;并行与浏览器管理更现代 | 新项目选 Playwright 省一半维护量 对比要点 |
| 定位策略 · 语义优先 | get_by_role / get_by_label / get_by_text 按用户可感知语义定位,最贴近真实使用且最抗重构 | 推荐顺序第一位 |
| 定位策略 · CSS / XPath | CSS 选择器性能好、够用;XPath 能按层级与文本找元素但更脆弱,绝对路径一律禁用 | data-testid 专用属性最稳 语义兜底 |
| 显式等待 | 按条件等待:元素可见、可点击、文本出现才继续;是三类等待中唯一推荐的生产用法 | WebDriverWait + expected_conditions 首选 |
| 隐式等待 | 全局设置元素查找的轮询超时;与显式等待混用会导致等待时间叠加且行为难预测 | 避免混用 |
| 强制等待 | 固定 sleep 死等:网络快了浪费时间、网络慢了照样挂,是 flaky 用例的头号来源 | 仅限临时调试 用例中禁用 |
| POM 页面对象模式 | 每个页面封装一个类:元素定位与页面操作收在页对象里,用例只写业务流程 | 页面变了只改一处 结构与用例分离 |
🔌 接口自动化
| 主题 | 说明 | 要点 |
|---|---|---|
| 用例分层 · 单接口 | 参数校验、异常码、鉴权、边界值:执行快、定位准,是接口回归集的量与底盘 | 量大管饱 |
| 用例分层 · 场景链 | 多接口串成业务流(下单 → 支付 → 退款),上下游字段取值传递,验证状态机流转 | 关注接口间依赖与数据传递 业务闭环 |
| 用例分层 · 资损类 | 金额计算、重复支付、幂等、并发扣减:必测且单独打标,失败按最高优先级处理 | 单独标记必测 |
| 断言 · 状态码与结构 | 第一层断言 HTTP 状态码语义正确,第二层断言 JSON 结构与关键字段存在、类型正确 | 先结构后取值,失败信息更可读 |
| 断言 · 业务字段与 DB | 关键业务字段精确断言;金额、状态等落库值与接口返回、DB 记录三方交叉校验 | 落库校验防假成功 |
| 数据驱动 · CSV / YAML | 一份用例逻辑配多份数据文件,pytest 用 parametrize 或外部文件驱动,新增场景只加数据 | 逻辑与数据分离 |
| 数据驱动 · 工厂方法 | 造数工厂生成带「有效默认值」的请求对象,用例只覆盖与场景相关的差异字段 | 新增字段不破坏全量用例 屏蔽无关字段 |
📱 App 自动化
| 主题 | 说明 | 要点 |
|---|---|---|
| Appium 架构一句话 | WebDriver 协议统一测试指令,Appium Server 把指令翻译给各平台驱动(Android 的 UiAutomator2 / iOS 的 XCUITest)在真机或模拟器上执行 | 一套 API 双平台 |
| Android 差异要点 | adb 管理设备、UiAutomator2 驱动执行、uiautomatorviewer / Appium Inspector 定位元素、权限可在安装时自动授予 | 设备碎片化需多分辨率覆盖 生态开放 |
| iOS 差异要点 | 依赖 macOS + Xcode + XCUITest 驱动,应用必须开发者签名;元素定位体系与 Android 不同 | 环境搭建成本高 签名是前置条件 |
| 稳定性 · 等待策略 | 以元素可见 / 可点击的条件等待为主,兼顾页面加载与动画时长;避免固定 sleep | 条件等待优先 |
| 稳定性 · 权限弹窗 | 启动时统一处理系统权限弹窗:Android 配 autoGrantPermissions,iOS 预置弹窗自动点击,避免用例被随机弹窗打断 | 弹窗前置治理 |
🤖 CI 集成
自动化测试不进流水线就只是脚本:触发分层、门禁卡点、报告可查,才算资产。
| 主题 | 说明 | 要点 |
|---|---|---|
| 触发 · 提交触发 | 每次 push / PR 跑核心冒烟集,控制在 10~15 分钟内,快速反馈挡住低级回归 | 分钟级反馈 |
| 触发 · 定时回归 | 夜间跑全量回归集,白天上班先看报告、把失败用例分派到责任人 | 快慢分离 |
| 触发 · 发布门禁 | 核心链路用例 100% 通过才允许发布;豁免必须写明理由与风险,留痕可查 | 门禁不容讨价还价 |
| Allure 一句话 | 测试报告框架:按 feature / story 组织用例,附步骤、截图、日志附件,失败原因一眼可查 | 报告即看板 |
| 失败重试策略 | 仅对网络 / 环境类失败做有限重试(如 2 次),且每次重试必须记录进报告;重试率升高说明有系统性问题 | 重试掩盖症状不治根因 |
| 告警分级 | 核心链路失败 → 即时群通知 @ 责任人;非核心失败 → 每日汇总邮件,避免告警疲劳 | 分级通知降噪 |
🧯 稳定性治理
| 主题 | 说明 | 要点 |
|---|---|---|
| 成因一 · 等待滥用 | 固定 sleep 太短环境一慢就挂、太长拖慢整体;环境抖动被放大成用例失败 | 改条件等待 flaky 头号来源 |
| 成因二 · 环境依赖 | 共享环境被他人改配置、第三方接口抖动、测试设备被占用,用例随环境起舞 | 关键依赖 mock 或独立测试环境 |
| 成因三 · 数据污染 | 用例间共享数据互相干扰、历史脏数据累积,换个执行顺序就失败 | 数据自造自清理 三大成因 |
| 隔离 · 独立账号与数据 | 并发执行的用例使用独立账号与独立数据集,从物理上消除相互影响 | 物理隔离 |
| 隔离 · 用后清理 | fixture / teardown 保证「谁创建谁销毁」;清理失败也要留痕,宁可多跑一条清理用例 | 用完即净 |
| 维护节奏与责任人 | flaky 用例先移出回归集、挂看板限期修复;每条用例明确责任人,需求变更时同步维护用例 | 无主用例必腐化 |
🎬 Playwright 起步脚本
一条能直接跑通的最小用例:运行器自动 launch 浏览器 → goto 打开页面 → getByRole 语义定位点击 → expect 自动重试断言 → trace 回放与截图留证据。
import { test, expect } from '@playwright/test';
test('登录成功进入工作台', async ({ page }) => {
// 0. 运行器已自动 launch 浏览器;脱离 runner 时可手动:await chromium.launch()
// 先开启 trace:失败时可在报告里逐步回放操作,定位不靠猜
await page.context().tracing.start({ snapshots: true, screenshots: true });
// 1. 打开登录页
await page.goto('https://app.example.com/login');
// 2. 语义定位:按可访问角色 + 名称找元素,比 class / id 更抗前端重构
await page.getByRole('textbox', { name: '用户名' }).fill('qa-user');
await page.getByLabel('密码').fill('pass-123');
// 3. 点击登录按钮
await page.getByRole('button', { name: '登录' }).click();
// 4. expect 断言自带自动重试:默认 5s 内轮询等待,绝不手写 sleep
await expect(page).toHaveURL(/.*dashboard/);
await expect(page.getByRole('heading', { name: '工作台' })).toBeVisible();
// 5. 收尾留证据:trace 落盘可在报告中回放,整页截图随报告归档
await page.context().tracing.stop({ path: 'trace.zip' });
await page.screenshot({ path: 'dashboard.png', fullPage: true });
});
🎯 元素定位避坑
| 避坑点 | 反例 → 正解 | 一句话要点 |
|---|---|---|
| 不用绝对 XPath | /html/body/div[2]/div[1]/table[3]/... 前端一调布局全部失效 → 换语义定位或稳定属性 | 绝对路径禁止进代码库 最脆弱定位 |
| 优先语义定位 | getByRole / getByLabel / getByText 按用户视角找元素;语义缺失本身就是可访问性缺陷,顺手推动前端补齐 | 页面越好用例越稳 抗重构首选 |
| 动态 id 用 data-testid | 构建生成的 id(如 field-8f3a2)每次都变 → 与前端约定 data-testid 专用属性,只用于测试不参与样式 | 定位与样式彻底解耦 专属测试属性 |
| 等待用 expect 自动重试 | waitForTimeout(3000) 网络慢必挂、快了白等 → 改 await expect(el).toBeVisible() 轮询到出现为止 | 硬等待是 flaky 头号来源 拒绝 sleep |
| iframe 需先切 frame | 在父文档直接找 iframe 内元素必然超时 → 用 page.frameLocator('#editor').getByText('…') 切入再定位,操作完切回主文档 | 切进去、做完、切回来 先切域再找 |