QA & Testing Engine — Complete Software Quality System
人工智能代理的终极测试方法论。从测试策略到执行,覆盖范围到报告 —— 发布高质量软件所需的一切。
第一阶段:测试策略设计
在编写单个测试之前,设计策略。
策略简报模板
项目:
名称: ""
类型: web-app | api | mobile | library | cli | data-pipeline
语言: [typescript, python, go, java],
框架: [react, express, django, spring]
风险概况:
数据敏感性: low | medium | high | critical # PII, financial, health
用户影响: internal | b2b | b2c | life-safety
部署频率: daily | weekly | monthly
监管: [none, SOC2, HIPAA, PCI-DSS, GDPR]
测试范围:
在范围内: [] # 功能、服务、组件
在范围外: [] # 明确排除(附理由)
环境:
开发: { url: "", db: "local" }
预生产: { url: "", db: "seeded" }
生产: { url: "", smoke_only: true }
测试类型决策矩阵
| 风险概况 | 单元 | 集成 | E2E | 性能 | 安全 | 可访问性 |
|---|---|---|---|---|---|---|
| 内部工具 | ✅ 核心 | ✅ API | ⚠️ 快乐路径 | ❌ | ⚠️ 基础 | ❌ |
| B2B SaaS | ✅ 全部 | ✅ 全部 | ✅ 关键流程 | ✅ 负载 | ✅ OWASP Top 10 | ✅ WCAG AA |
| B2C 高流量 | ✅ 全部 | ✅ 全部 | ✅ 全部 | ✅ 压力 + 浸泡 | ✅ 全部 | ✅ WCAG AA |
| 金融/健康 | ✅ 全部 + 变异 | ✅ 全部 + 合同 | ✅ 全部 + 混沌 | ✅ 全套 | ✅ 渗透测试 | ✅ WCAG AAA |
测试金字塔架构
/ E2E \ 5-10% — 仅关键用户旅程
/ 集成 \ 20-30% — API合同,服务边界
/ 单元测试 \ 60-70% — 业务逻辑,纯函数
反模式:冰淇淋锥 —— 比单元测试更多的E2E。慢,不稳定,昂贵。通过将测试覆盖向下推金字塔来修复。
反模式:沙漏 —— 很多单元 + E2E,没有集成。错过服务之间的合同错误。
第二阶段:单元测试精通
AAA模式(Arrange-Act-Assert)
每个单元测试都遵循这个结构:
describe('PricingCalculator', () => {
// 按行为分组,而不是方法
describe('当客户有批量折扣时', () => {
it('应用分层定价超过阈值', () => {
// 安排 — 设置场景
const calculator = new PricingCalculator();
const customer = createCustomer({ tier: 'enterprise', units: 150 });
// 行动 — 执行被测试的行为
const price = calculator.calculate(customer);
// 断言 — 验证结果(一个逻辑断言)
expect(price).toEqual({
subtotal: 12000,
discount: 1800, // 15% 批量折扣
total: 10200,
});
});
});
});
测试命名约定
格式: [unit] [scenario] [expected behavior]
✅ 好:
PricingCalculator 在单位超过100时应用15%折扣UserService 在用户ID无效时抛出NotFoundErrorparseDate 对于畸形ISO字符串返回null
❌ 坏:
test1,should work,calculates price
单元测试的优先顺序
- 业务逻辑 — 定价,规则,计算,状态机
- 数据转换 — 解析器,格式化程序,序列化器,映射器
- 边缘情况 — 边界,null/undefined,空集合,溢出
- 错误处理 — 每个
catch块,每个验证路径 - 纯函数 — 最容易测试,ROI最高
不要单元测试什么
- 框架内部(React渲染,Express路由)
- 没有逻辑的简单getter/setter
- 第三方库行为
- 实现细节(私有方法,内部状态)
模拟规则
| 依赖类型 | 策略 | 示例 |
|---|---|---|
| 数据库 | 模拟仓库/DAO | jest.mock('./userRepo') |
| HTTP API | 模拟客户端或使用MSW | msw.http.get('/api/users', ...) |
| 文件系统 | 模拟fs或使用临时目录 | jest.mock('fs/promises') |
| 时间/日期 | 假定时器 | jest.useFakeTimers() |
| 随机性 | 种子或模拟 | jest.spyOn(Math, 'random') |
| 环境 | 覆盖环境变量 | process.env.NODE_ENV = 'test' |
规则:在边界处模拟,不在内部。 如果你正在模拟一个你自己的类,你的设计可能需要重构。
覆盖率目标
| 指标 | 最低 | 好 | 优秀 |
|---|---|---|---|
| 行覆盖率 | 70% | 85% | 95%+ |
| 分支覆盖率 | 60% | 80% | 90%+ |
| 函数覆盖率 | 75% | 90% | 95%+ |
| 关键路径覆盖率 | 100% | 100% | 100% |
警告: 100%覆盖率 ≠ 质量。覆盖率衡量哪些代码运行了,而不是哪些被验证了。没有断言的测试有覆盖率但没有价值。
第三阶段:集成测试
API测试清单
对于每个API端点,测试:
端点:POST /api/orders
测试:
快乐路径:
- 有效请求返回201与订单ID
- 响应匹配模式
- 数据库记录正确创建
- 事件/webhooks触发
验证:
- 缺少必填字段 → 400与字段错误
- 无效数据类型 → 400与类型错误
- 业务规则违规 → 422与解释
认证:
- 无令牌 → 401
- 令牌过期 → 401
- 错误角色 → 403
- 有效令牌 → 继续
边缘情况:
- 重复请求(幂等性)→ 相同响应
- 并发请求 → 无竞态条件
- 最大有效载荷大小 → 413或优雅处理
- 输入中的特殊字符 → 无注入
错误处理:
- 数据库故障 → 503与重试提示
- 外部服务超时 → 504或回退
- 速率限制超过 → 429与重试后
合同测试
当服务通信时,测试合同:
合同:
消费者:order-service
提供者:payment-service
交互:
- 描述:"处理支付"
请求:
方法:POST
路径:/payments
主体:
amount: 99.99
currency: USD
order_id: "ord_123"
响应:
状态:200
主体:
payment_id: "pay_xxx" # 字符串,不为空
status: "completed" # 枚举:completed|pending|failed
破坏性变更: # 没有版本控制永远不要这样做
- 从响应中移除字段
- 更改字段类型
- 添加请求的必填字段
- 更改URL路径
- 更改错误响应格式
数据库测试规则
- 每个测试都得到一个清洁状态 — 使用事务回滚或在测试之间截断
- 使用工厂,而不是固定装置 —
createUser({ role: 'admin' })> 硬编码SQL转储 - 测试迁移 — 运行迁移上,迁移下,迁移上(往返)
- 测试约束 — 唯一违规,FK级联,NOT NULL
- 测试查询 — 特别是复杂的JOINs,聚合,窗口函数
第四阶段:端到端测试
关键用户旅程映射
识别并测试生成收入或阻碍用户的流程:
关键旅程:
- 名称:"注册 → 第一个价值"
步骤:
- 访问着陆页
- 点击注册
- 填写注册表单
- 验证电子邮件
- 完成入职
- 执行第一个关键动作
最大持续时间:3分钟
- 名称:"购买流程"
步骤:
- 浏览产品
- 添加到购物车
- 输入运输
- 输入支付
- 确认订单
- 接收确认电子邮件
最大持续时间:2分钟
- 名称:"登录 → 核心任务 → 注销"
步骤:
- 登录(密码 + SSO + MFA变体)
- 导航到核心功能
- 完成主要工作流程
- 验证结果
- 注销
最大持续时间:1分钟
E2E最佳实践
- 测试用户行为,而不是实现 — 通过文本/角色点击按钮,而不是CSS类
- 适度使用data-testid — 仅当没有可访问的选择器存在时
- 等待状态,而不是时间 —
waitFor(element)不是sleep(3000) - 隔离测试数据 — 每个测试创建自己的用户/数据
- 在CI中运行并重试 — 对于不稳定的网络,重试1次,如果>5%的波动率则调查
选择器优先级(最好 → 最差)
getByRole('button', { name: 'Submit' })— 可访问的,弹性的getByLabelText('Email')— 特定于表单的,可访问的getByText('Welcome back')— 基于内容的getByTestId('submit-btn')— 显式的测试钩子querySelector('.btn-primary')— ❌ 脆弱的,CSS变化时会中断
波动测试分类
| 症状 | 可能的原因 | 修复 |
|---|---|---|
| 本地通过,在CI中失败 | 定时/竞态条件 | 添加显式等待,检查CI资源限制 |
| 间歇性失败 | 测试之间的共享状态 | 隔离测试数据,重置状态 |
| 部署后失败 | 环境差异 | 检查环境变量,API版本,功能标志 |
| 特定时间失败 | 时间依赖逻辑 | 模拟日期/时间,避免时间敏感的断言 |
| 平行运行失败 | 资源争用 | 使用每个工作器的唯一端口/DBs |
规则:在24小时内隔离波动测试。 每个人都忽略的波动测试套件比没有测试更糟糕。
第五阶段:性能测试
负载测试设计
性能测试:
烟雾:
vus: 5
持续时间:1m
目的:"验证测试工作"
负载:
vus: 100 # 预期的并发用户
持续时间:10m
上升:2m
目的:"正常流量行为"
阈值:
p95_response: <500ms
error_rate: <1%
压力:
vus: 300 # 3倍预期负载
持续时间:15m
上升:5m
目的:"找到断裂点"
浸泡:
vus: 80
持续时间:2h
目的:"内存泄漏,连接耗尽"
尖峰:
阶段:
- { vus: 50, 持续时间:2m }
- { vus: 500, 持续时间:30s } # 突然尖峰
- { vus: 50, 持续时间:2m }
目的:"恢复行为"
性能预算
| 指标 | Web App | API | 后台作业 |
|---|---|---|---|
| 响应时间(p50) | <200ms | <100ms | N/A |
| 响应时间(p95) | <1s | <500ms | N/A |
| 响应时间(p99) | <3s | <1s | N/A |
| 吞吐量 | >100 rps | >500 rps | >1000/min |
| 错误率 | <0.1% | <0.1% | <0.5% |
| CPU使用率 | <70% | <70% | <90% |
| 内存增长 | <5%/hr | <2%/hr | <10%/hr |
数据库性能测试
数据库性能:
查询测试:
- 名称:"仪表板聚合查询"
基线:50ms
最大可接受:200ms
1M行:测量
10M行:测量
索引验证:
- 运行EXPLAIN ANALYZE所有关键查询
- 验证大于10K行的表上没有顺序扫描
- 每周检查索引使用统计信息
连接池:
- 在最大连接处测试
- 验证池耗尽时的优雅处理
- 监控连接等待时间
第六阶段:安全测试
OWASP Top 10测试清单
安全测试:
A01_broken_access_control:
- [ ] 水平权限提升(访问其他用户的数据)
- [ ] 垂直权限提升(访问管理员功能)
- [ ] IDOR(不安全的直接对象引用)
- [ ] 缺少函数级访问控制
- [ ] CORS配置错误
A02_cryptographic_failures:
- [ ] 传输中的敏感数据(TLS 1.2+)
- [ ] 静态敏感数据(加密)
- [ ] 密码哈希(bcrypt/argon2,不是MD5/SHA)
- [ ] 代码/日志/URL中无秘密
A03_injection:
- [ ] SQL注入(参数化查询)
- [ ] NoSQL注入
- [ ] 命令注入(操作系统命令)
- [ ] XSS(存储,反射,基于DOM)
- [ ] 模板注入(SSTI)
A04_insecure_design:
- [ ] 认证端点的速率限制
- [ ] 连续N次失败后锁定账户
- [ ] 公共表单上的CAPTCHA
- [ ] 业务逻辑滥用场景
A05_security_misconfiguration:
- [ ] 移除默认凭据
- [ ] 错误消息不泄露堆栈跟踪
- [ ] 设置安全头(CSP, HSTS, X-Frame-Options)
- [ ] 禁用目录列表
- [ ] 禁用不必要的HTTP方法
A07_auth_failures:
- [ ] 防止暴力破解
- [ ] 会话固定
- [ ] 会话超时
- [ ] JWT验证(签名,到期,发行者)
- [ ] MFA绕过尝试
输入验证测试负载
测试每个用户输入与:
注入负载:
sql: ["' OR 1=1--", "'; DROP TABLE users;--", "1 UNION SELECT * FROM users"]
xss: ["<script>alert(1)</script>", "<img onerror=alert(1) src=x>", "javascript:alert(1)"]
路径遍历:["../../etc/passwd", "..\\..\\windows\\system32", "%2e%2e%2f"]
命令:["; ls -la", "| cat /etc/passwd", "$(whoami)", "`id`"]
边界值:
字符串:["", " ", "a"*10000, null, undefined, "表情符号:🎯", "Unicode:é à ü", "RTL:مرحبا"]
数字:[0, -1, 2147483647, -2147483648, NaN, Infinity, 0.1+0.2]
数组:[[], [null], Array(10000)]
日期:["1970-01-01", "2099-12-31", "invalid-date", "2024-02-29", "2023-02-29"]
第七阶段:测试自动化架构
框架选择指南
| 需要 | JavaScript/TS | Python | Go | Java |
|---|---|---|---|---|
| 单元 | Vitest / Jest | pytest | testing + testify | JUnit 5 |
| API | Supertest | httpx + pytest | net/http/httptest | RestAssured |
| E2E(浏览器) | Playwright | Playwright | chromedp | Selenium |
| 性能 | k6 | Locust | vegeta | Gatling |
| 合同 | Pact | Pact | Pact | Pact |
| 安全 | ZAP + 自定义 | Bandit + 自定义 | gosec | SpotBugs |
CI管道测试阶段
管道:
第一阶段快速: # <2分钟,阻止PR
- 代码检查 + 类型检查
- 单元测试
- 安全:依赖扫描(npm audit / safety)
第二阶段彻底: # <10分钟,阻止合并
- 集成测试
- 合同测试
- 安全:SAST扫描
- 覆盖率报告 + 阈值检查
第三阶段信心: # <30分钟,阻止部署
- E2E关键旅程
- 视觉回归(如适用)
- 安全:容器扫描
第四阶段部署后: # 部署到预生产后
- 对预生产的烟雾测试
- 性能基线检查
- 安全:DAST扫描(ZAP)
第五阶段生产: # 生产部署后
- 烟雾测试(仅关键路径)
- 启用合成监控
- 金丝雀指标监控
测试数据管理
测试数据策略:
单元测试:
方法:工厂 # 构建者模式,创建你需要的确切东西
示例:"createUser({ role: 'admin', plan: 'enterprise' })"
集成测试:
方法:种子数据库
重置:每个测试套件 # 事务回滚或截断
敏感数据:匿名化 # 永远不要使用真实的PII
e2e测试:
方法:api设置 # 通过API在测试前创建数据
清理:每个之后 # 删除创建的数据
隔离:唯一标识符 # 时间戳或UUID在测试数据中
性能测试:
方法:代表性数据集
体积:10x生产 # 测试比生产更多的数据
生成:faker库 # 真实但合成的
第八阶段:质量度量和报告
测试健康仪表板
指标:
测试套件健康:
总测试:0
通过:0
失败:0
跳过:0 # >5%跳过 = 技术债务警报
波动:0 # >2%波动 = 立即隔离
覆盖率:
行:"0%"
分支:"0%"
关键路径:"0%" # 必须是100%
执行:
单元持续时间:"0s" # 目标:<30s
集成持续时间:"0s" # 目标:<5m
e2e持续时间:"0s" # 目标:<15m
总CI时间:"0s" # 目标:<20m
缺陷度量:
测试中发现的缺陷:0
逃到生产的缺陷:0
逃逸率:"0%" # 目标:<5%
mttr:"0h" # 解决方案的平均时间
趋势: # 每周跟踪
新增测试:0
删除的测试:0 # 健康的删除 = 删除多余的测试
覆盖率变化:"+0%"
波动率变化:"+0%"
测试报告模板
# 测试报告 — [功能/冲刺/发布]
## 摘要
- **状态:** ✅ PASS / ⚠️ PASS WITH RISKS / ❌ FAIL
- **运行的测试:** X | **通过:** X | **失败:** X | **跳过:** X
- **覆盖率:** 行X% | 枝X% | 关键100%
- **持续时间:** Xm Xs
## 关键发现
### 🔴 临界(阻止发布)
1. [发现] — [影响] — [修复建议]
### 🟡 高(在下一次发布之前修复)
1. [发现] — [影响] — [修复建议]
### 🟢 中/低(待办事项)
1. [发现] — [影响]
## 风险评估
- **未测试区域:** [列表]
- **已知波动测试:** [带票ID的列表]
- **性能问题:** [如果有]
## 建议
[发货 / 发货监控 / 等待修复]
质量得分(0-100)
| 维度 | 权重 | 评分 |
|---|---|---|
| 测试覆盖率 | 20% | <60%=0, 60-70%=5, 70-80%=10, 80-90%=15, 90%+=20 |
| 关键路径覆盖率 | 20% | <100%=0, 100%=20 |
| 缺陷逃逸率 | 15% | >10%=0, 5-10%=5, 2-5%=10, <2%=15 |
| 测试套件速度 | 10% | >30m=0, 20-30m=3, 10-20m=7, <10m=10 |
| 波动率 | 10% | >5%=0, 2-5%=3, 1-2%=7, <1%=10 |
| 安全测试覆盖率 | 10% | 无=0, 基本=3, OWASP Top 10=7, 全部=10 |
| 文档 | 5% | 无=0, 基本=2, 完整=5 |
| 自动化比率 | 10% | <50%=0, 50-70%=3, 70-90%=7, 90%+=10 |
评分: 0-40 = 🔴 临界 | 41-60 = 🟡 需要工作 | 61-80 = 🟢 好 | 81-100 = 💎 优秀
第九阶段:专业测试
可访问性测试(WCAG 2.1)
可访问性检查清单:
级别a: # 最低合规性
- [ ] 所有图像都有alt文本
- [ ] 所有表单输入都有标签
- [ ] 颜色不是唯一的视觉指示器
- [ ] 页面有适当的标题层次(h1→h2→h3)
- [ ] 所有功能都可以通过键盘使用
- [ ] 焦点可见且逻辑
- [ ] 没有内容闪烁>3次/秒
级别aa: # 标准合规性(推荐)
- [ ] 颜色对比度比≥4.5:1(普通文本)
- [ ] 颜色对比度比≥3:1(大文本)
- [ ] 文本可调整至200%无损
- [ ] 跳过导航链接
- [ ] 跨页面的一致导航
- [ ] 提供错误建议
- [ ] ARIA地标页面区域
工具:
- axe-core(自动化,捕获~30%的问题)
- Lighthouse可访问性审核
- 手动键盘导航测试
- 屏幕阅读器测试(VoiceOver/NVDA)
API向后兼容性测试
兼容性测试:
更新API时:
- [ ] 所有现有字段仍然出现在响应中
- [ ] 没有字段类型变化(字符串→数字)
- [ ] 新的必填请求字段有默认值
- [ ] 弃用的字段仍然工作(带有警告头)
- [ ] 错误格式未改变
- [ ] 分页行为未改变
- [ ] 速率限制未减少
版本控制策略:
- URL版本控制:/v1/users, /v2/users
- 头部版本控制:Accept: application/vnd.api+json;version=2
- 弃用版本的日落头
- 至少6个月的弃用通知
混沌工程原则
混沌测试:
网络:
- 服务依赖性下降 → 优雅降级?
- 网络延迟增加10倍 → 超时处理?
- DNS解析失败 → 回退行为?
基础设施:
- 数据库主故障 → 副本提升?
- 缓存(Redis)下降 → DB回退工作?
- 磁盘填满 → 警报+优雅失败?
应用:
- 内存压力 → OOM处理?
- CPU饱和 → 请求排队?
- 证书到期 → 监控警报?
数据:
- 队列中的消息损坏 → 死信+警报?
- 模式迁移中途失败 → 回滚工作?
- 服务之间的时钟偏差 → 幂等性保持?
第十阶段:日常QA工作流程
对于新功能
- 审查需求 — 在编写代码之前识别测试场景(左移)
- 编写测试用例 — 涵盖快乐路径,边缘情况,错误情况,安全
- 审查PR测试 — 测试有意义吗?它们测试行为,而不是实现?
- 运行完整套件 — 单元 + 集成 + E2E受影响区域
- 报告结果 — 使用上述测试报告模板
对于错误修复
- 首先编写失败的测试 — 将错误作为测试重现
- 验证修复使测试通过 — 测试是证明
- 检查回归 — 运行相关测试套件
- 添加到回归套件 — 错误测试防止重新引入
每周QA审查
每周审查:
星期一:
- 审查波动测试隔离 — 修复或删除
- 检查覆盖率趋势 — 下降 = 技术债务
- 审查逃逸缺陷 — 更新测试策略
星期五:
- 更新测试健康仪表板
- 清理过时的测试
- 记录发现的新测试模式
- 计划下周的测试重点
自然语言命令
“为[项目/功能]创建测试策略”→ 完整的策略简报“为[函数/类]编写单元测试”→ AAA模式测试,带边缘情况“测试此API端点:[method] [path]”→ 完整的API测试清单“审查这些测试的质量”→ 测试代码审查与评分“生成性能测试计划”→ k6/Locust测试设计“安全测试[功能/端点]”→ 基于OWASP的测试清单“为[发布]创建测试报告”→ 格式化的测试报告“我们的测试健康状况如何?”→ 带有指标和建议的仪表板“找出我们的测试覆盖率差距”→ 分析与优先建议“帮助调试这个波动测试”→ 根本原因分析与修复建议“设置CI测试管道”→ 阶段性管道配置“对[页面/组件]进行可访问性审计”→ WCAG清单与发现