当前位置: 首页 > news >正文

CI 中的测试策略分层:smoke、integration 与 e2e 的执行时机

CI 中的测试策略分层:smoke、integration 与 e2e 的执行时机

CI 里跑全量 e2e 测试要 45 分钟——每次提交都跑,开发者等得比写代码还久。

一、场景痛点

你的 CI 流程在每次 push 时跑全量测试:500 个单元测试(2 分钟)+ 200 个集成测试(10 分钟)+ 50 个 e2e 测试(45 分钟)。总耗时 57 分钟。开发者一天提交 10 次,累计等待 570 分钟(9.5 小时)——比实际工作时间还长。

核心矛盾:不是所有测试都需要在每次提交时跑——smoke 测试每次跑(快),集成测试合并时跑(中等),e2e 测试发布前跑(慢)

二、底层机制与原理剖析

2.1 测试金字塔与执行时机

2.2 smoke 测试的定义

smoke 不是"跑几个单元测试",而是"验证系统核心功能是否可用"的精选子集:

  • 核心业务流程(登录→下单→支付):5 个 e2e
  • 关键 API 可达性(/health、/api/v1/status):10 个集成
  • 核心单元测试(数据校验、认证逻辑):50 个单元
  • 总计约 65 个,耗时 3-5 分钟

三、生产级代码实现

3.1 GitHub Actions 分层测试配置

# .github/workflows/test-tiered.yaml —— 分层测试 CI 配置 name: Tiered Test Pipeline on: push: branches: ['*'] # 每次 push 跑 smoke pull_request: branches: [main] # PR merge 跑 unit + integration workflow_dispatch: # 手动触发全量 e2e jobs: # Tier 1: smoke 测试 — 每次 push 触发,3-5 分钟 smoke: runs-on: ubuntu-latest if: github.event_name == 'push' steps: - uses: actions/checkout@v4 - name: Install dependencies run: npm ci - name: Run smoke tests run: npm run test:smoke # test:smoke 脚本:只跑精选的 65 个关键测试 # 脚本定义在 package.json: # "test:smoke": "jest --testPathPattern='smoke/' --maxWorkers=4" # Tier 2: 单元 + 集成测试 — PR merge 触发,12 分钟 unit-integration: runs-on: ubuntu-latest if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v4 - name: Install dependencies run: npm ci - name: Run unit tests run: npm run test:unit - name: Run integration tests run: npm run test:integration # 集成测试需要数据库:用 Docker 启动临时数据库 - name: Setup test database run: docker-compose -f docker-compose.test.yaml up -d db - name: Run integration tests run: npm run test:integration - name: Teardown test database if: always() run: docker-compose -f docker-compose.test.yaml down # Tier 3: 全量 e2e 测试 — 发布前手动触发,45 分钟 e2e-full: runs-on: ubuntu-latest if: github.event_name == 'workflow_dispatch' steps: - uses: actions/checkout@v4 - name: Setup full test environment run: docker-compose -f docker-compose.test.yaml up -d - name: Run e2e tests run: npm run test:e2e # e2e 测试跑在完整环境中:所有服务 + 真实数据库 # 超时设置:单个 e2e 测试最长 5 分钟 env: TEST_TIMEOUT: 300000 - name: Teardown if: always() run: docker-compose -f docker-compose.test.yaml down

3.2 smoke 测试精选脚本

// jest.smoke.config.ts —— smoke 测试配置:只跑关键路径 export default { // 只跑 smoke 目录下的测试 testPathPattern: 'smoke/', // 并行执行:4 个 worker 加速 maxWorkers: 4, // 超时:单个 smoke 测试最长 10 秒 testTimeout: 10000, // 失败策略:第一个失败就停止(smoke 测试失败 = 核心功能不可用) bail: 1, }; // smoke/api-health.test.ts —— API 可达性 smoke 测试 describe('API Smoke Tests', () => { test('Health endpoint is reachable', async () => { const response = await fetch(`${API_URL}/health`); expect(response.status).toBe(200); }); test('Core API v1 status endpoint', async () => { const response = await fetch(`${API_URL}/api/v1/status`); expect(response.status).toBe(200); }); test('Authentication endpoint works', async () => { const response = await fetch(`${API_URL}/api/v1/auth/login`, { method: 'POST', body: JSON.stringify({ username: 'test', password: 'test' }), }); expect(response.status).toBeLessThan(500); // 不期望 500 错误 }); }); // smoke/core-flow.test.ts —— 核心业务流程 smoke 测试 describe('Core Business Flow Smoke', () => { test('Login → Create Order → Pay flow', async () => { // Step 1: 登录 const loginRes = await fetch(`${API_URL}/api/v1/auth/login`, { method: 'POST', body: JSON.stringify({ username: 'smoke_test', password: 'smoke_pass' }), }); const { token } = await loginRes.json(); expect(token).toBeDefined(); // Step 2: 创建订单 const orderRes = await fetch(`${API_URL}/api/v1/orders`, { method: 'POST', headers: { Authorization: `Bearer ${token}` }, body: JSON.stringify({ product_id: 'smoke-product', quantity: 1 }), }); const { order_id } = await orderRes.json(); expect(order_id).toBeDefined(); // Step 3: 支付 const payRes = await fetch(`${API_URL}/api/v1/payments`, { method: 'POST', headers: { Authorization: `Bearer ${token}` }, body: JSON.stringify({ order_id, method: 'mock' }), }); expect(payRes.status).toBeLessThan(500); }); });

四、边界分析与架构权衡

4.1 smoke 测试的覆盖盲区

smoke 只验证核心流程,不验证边界条件(并发冲突、数据校验、异常恢复)。如果核心流程通过但边界条件有 bug,smoke 不会发现。

对策:smoke 是"快速兜底",不是"完整验证"。完整验证靠集成测试和 e2e 测试。smoke 的目标是在 3 分钟内告诉你"核心功能是否还活着"。

4.2 e2e 测试的脆弱性

e2e 测试依赖完整环境,环境问题(数据库重启、网络抖动)会导致测试失败,但不是代码 bug。e2e 测试的失败率约 5-10% 是环境问题,不是应用问题。

对策:e2e 测试失败后自动重试一次。如果重试仍失败,人工排查是否是环境问题。

4.3 适用边界与禁用场景

  • 适用:日提交 >5 次、团队 >3 人、测试总量 >200 个
  • 禁用:日提交 <2 次(等 57 分钟也没关系)、测试总量 <50 个(全量跑也很快)、紧急修复时(跳过 e2e 直接发布)

五、结语

CI 测试策略的核心是分层执行:smoke 每次 commit 跑(3-5 分钟),集成测试 PR merge 时跑(12 分钟),e2e 发布前跑(45 分钟)。开发者日常等待时间从 57 分钟降到 3-5 分钟。smoke 不是"跑几个测试",而是"验证核心功能是否可用"的精选子集——5 个核心 e2e + 10 个 API 可达性 + 50 个关键单元测试。e2e 测试只在发布前跑,不在每次提交时跑。e2e 的环境脆弱性用自动重试缓解。分层策略的前提是测试总数量足够多(>200 个),否则全量跑也很快。

资料说明

本文中的协议、版本、性能、成本和行业趋势应以可核验的一手资料为准。未标注统计口径的比例、时间表和预测仅作工程讨论,不应视为行业事实。可参考 0730 资料来源索引,并在发布前将具体来源贴到对应断言之后。

http://www.jsqmd.com/news/1291178/

相关文章:

  • 从A.dx到数值积分:工程实践中的微积分核心操作指南
  • # HarmonyOS ArkTS 小游戏开发实战(一):弹弹球物理碰撞游戏
  • STM32智能小车实战:从硬件选型到PID算法,手把手教你打造循迹机器人
  • 智能车图像处理:八邻域边界追踪与中心线提取实战指南
  • STM32主从定时器实现任意相位差PWM输出配置详解
  • 揭秘司法AI法条推荐准确率提升47%的关键:从语义理解到动态权重建模全流程拆解
  • Web安全核心:从数据流视角剖析SQL注入、反序列化与文件上传漏洞
  • 收到学术不端指控邮件后,千万别急着做这三件事——附英澳真实听证会案例
  • 2026年近期惠州五金外壳找哪家?5大优选厂商深度盘点 - 装修教育财税推荐2026
  • 2026AI智能纪要助力培训效果评估 准识别快整理更清晰更省事
  • 流批安卓自动点击神器,轻松搞定重复操作
  • Avatar骨骼映射:用大白话讲清楚这件事
  • 最新量化开发分阶段,工具和AI代码都要放对位置
  • 飞致云发布1Panel AI一体机产品家族
  • 从NPC台词到史诗终章:手把手教你用Diffusion+GraphRAG构建动态剧情树(含可商用许可清单)
  • Python第四次作业:从基础语法到实战项目全解析
  • 如何通过智能自动化工具提升英雄联盟游戏体验:League Akari完整指南
  • 实战从零构建Loop Engineering
  • Kimi K3大语言模型:许可证解析、本地部署与API集成指南
  • Java switch语句演进:从传统语法到模式匹配的实战指南
  • FPGA数字逻辑设计实战:基于Verilog的8路彩灯控制器完整开发指南
  • 从静态检索到自主规划:后端工程师的 Agentic RAG 实践手册
  • 5.20华为OD机试真题 新系统 - 多模型版本的最优调度 (JavaPyCC++JsGo)
  • Java通用树形结构工具类设计与实践
  • 深入浅出 Graph Engineering,看这篇就够了
  • 云原生 GitOps 终极武器:Argo CD 从原理到实战全解析
  • 在线png转jpg:系统只认jpg报格式错时跟着做 - 办公小帮手
  • UVa 664递归下降解析器实现与表达式求值技巧
  • LangChain 1.3实战:从零构建AI智能体与RAG系统完整指南
  • 从创意到代码:如何通过编程实践释放开发者创造力