3af119a598
- 新增 Vibe Coding 全栈相关演示组件 (DeveloperSkillShift, FrontendTriad, BackendCore 等) - 新增 RAG 相关组件 (RAGPipeline, ChunkingStrategy, Retrieval 等) - 新增 Embedding & Vector 相关组件 (EmbeddingConcept, VectorSimilarity 等) - 新增 AI Native App 设计组件 (AINativeArch, PromptDesign 等) - 新增 Infrastructure as Code 组件 (IaCConcept, TerraformWorkflow 等) - 新增 DNS & HTTPS 演示组件 (DnsResolution, HttpsHandshake 等) - 新增 Model Finetuning 组件 (FinetuningPipeline 等) - 更新多个章节的 markdown 内容,集成交互式演示
217 lines
7.9 KiB
Markdown
217 lines
7.9 KiB
Markdown
# 测试策略
|
||
|
||
::: tip 前言
|
||
**你的代码真的"没问题"吗?** 每次改完代码手动点一遍看看有没有坏——这种方式在项目小的时候还能凑合,但当代码量增长到几万行、团队扩展到十几人时,"手动点点看"就是一场灾难。
|
||
|
||
本章带你理解软件测试的核心策略,从测试金字塔到 TDD,建立系统化的质量保障思维。
|
||
:::
|
||
|
||
**这篇文章会带你学什么?**
|
||
|
||
| 章节 | 内容 | 核心概念 |
|
||
|-----|------|---------|
|
||
| **第 1 章** | 测试金字塔 | 测试的层次与比例 |
|
||
| **第 2 章** | 单元测试实战 | 如何写好一个测试 |
|
||
| **第 3 章** | TDD 驱动开发 | 红绿重构循环 |
|
||
| **第 4 章** | 测试策略选择 | 不同场景的方案 |
|
||
|
||
学完本章,你将理解如何为项目选择合适的测试策略,写出有价值的测试,并通过 TDD 提升代码设计质量。
|
||
|
||
---
|
||
|
||
## 0. 全景图:为什么需要自动化测试?
|
||
|
||
想象你是一个建筑工程师。每次修改图纸后,你不会亲自爬上每一层楼去检查结构是否安全——你会依赖一套**自动化的检测系统**。软件测试就是代码世界的"结构检测系统"。
|
||
|
||
::: tip 自动化测试的价值
|
||
- **回归保护**:修改 A 功能时,自动检测 B、C、D 功能是否被影响
|
||
- **重构信心**:有测试覆盖的代码,重构时心里有底
|
||
- **活文档**:好的测试就是最好的使用说明书
|
||
- **快速反馈**:几秒钟内知道代码是否正确,而不是等到部署后才发现问题
|
||
:::
|
||
|
||
---
|
||
|
||
## 1. 测试金字塔:测试的层次与比例
|
||
|
||
### 1.1 三层金字塔
|
||
|
||
Mike Cohn 提出的测试金字塔是测试策略的经典模型。它告诉我们:**不同类型的测试应该有不同的数量比例**。
|
||
|
||
通过下面的交互组件,点击金字塔的每一层,了解各层测试的特点:
|
||
|
||
<TestPyramidDemo />
|
||
|
||
### 1.2 为什么是金字塔形?
|
||
|
||
金字塔形状反映了一个核心权衡:**速度与真实度的取舍**。
|
||
|
||
- **底层(单元测试)**:速度极快、数量最多、成本最低,但只能验证单个零件
|
||
- **中层(集成测试)**:速度适中、数量适中,验证零件之间的配合
|
||
- **顶层(E2E 测试)**:最接近真实用户,但速度慢、维护成本高、容易因环境问题失败
|
||
|
||
> **反模式:冰淇淋甜筒** —— 如果你的项目 E2E 测试最多、单元测试最少,那就是倒过来的"冰淇淋甜筒"。这意味着测试套件运行缓慢、经常失败、维护成本极高。
|
||
|
||
---
|
||
|
||
## 2. 单元测试实战
|
||
|
||
### 2.1 什么是好的单元测试?
|
||
|
||
好的单元测试遵循 **FIRST** 原则:
|
||
|
||
| 原则 | 含义 | 说明 |
|
||
|------|------|------|
|
||
| **F**ast | 快速 | 毫秒级完成,开发者愿意频繁运行 |
|
||
| **I**ndependent | 独立 | 测试之间互不依赖,可以单独运行 |
|
||
| **R**epeatable | 可重复 | 任何环境下运行结果一致 |
|
||
| **S**elf-validating | 自验证 | 结果是明确的通过/失败,不需要人工判断 |
|
||
| **T**imely | 及时 | 在写代码的同时(或之前)写测试 |
|
||
|
||
### 2.2 测试的结构:AAA 模式
|
||
|
||
每个测试都应该有清晰的三段式结构:
|
||
|
||
```javascript
|
||
test('应该正确计算含税价格', () => {
|
||
// Arrange(准备)—— 设置测试数据
|
||
const price = 100
|
||
const taxRate = 0.13
|
||
|
||
// Act(执行)—— 调用被测函数
|
||
const result = calculateTotalWithTax(price, taxRate)
|
||
|
||
// Assert(断言)—— 验证结果
|
||
expect(result).toBe(113)
|
||
})
|
||
```
|
||
|
||
### 2.3 测试什么?不测什么?
|
||
|
||
**应该测试的:**
|
||
- 核心业务逻辑(价格计算、权限判断、数据转换)
|
||
- 边界条件(空值、零、负数、超大数)
|
||
- 错误处理路径
|
||
|
||
**不需要测试的:**
|
||
- 第三方库的内部实现
|
||
- 简单的 getter/setter
|
||
- 框架自身的功能(如 Vue 的响应式系统)
|
||
|
||
---
|
||
|
||
## 3. TDD:测试驱动开发
|
||
|
||
### 3.1 红绿重构循环
|
||
|
||
TDD(Test-Driven Development)的核心是一个简单的循环:**先写测试,再写实现,最后重构**。
|
||
|
||
通过下面的交互组件,亲自体验 TDD 的完整循环:
|
||
|
||
<TDDCycleDemo />
|
||
|
||
### 3.2 TDD 的三条规则
|
||
|
||
1. **不写任何产品代码,除非是为了让一个失败的测试通过**
|
||
2. **只写刚好让测试失败的测试代码**(编译不过也算失败)
|
||
3. **只写刚好让测试通过的产品代码**
|
||
|
||
### 3.3 TDD 的真正价值
|
||
|
||
TDD 的价值不仅在于"先写测试",更在于它**迫使你思考接口设计**。当你先写测试时,你是站在"使用者"的角度思考:这个函数应该接收什么参数?返回什么结果?这自然会导向更好的 API 设计。
|
||
|
||
::: tip TDD 不是银弹
|
||
TDD 适合逻辑密集的代码(算法、业务规则、数据转换),但对于 UI 布局、探索性原型等场景,强制 TDD 反而会拖慢速度。关键是理解它的思想,灵活运用。
|
||
:::
|
||
|
||
---
|
||
|
||
## 4. 测试策略选择
|
||
|
||
### 4.1 不同项目的测试重点
|
||
|
||
| 项目类型 | 测试重点 | 推荐比例 |
|
||
|----------|----------|----------|
|
||
| **工具库/SDK** | 单元测试为主 | 90% 单元 + 10% 集成 |
|
||
| **API 服务** | 集成测试为主 | 30% 单元 + 60% 集成 + 10% E2E |
|
||
| **Web 应用** | 均衡分布 | 50% 单元 + 30% 集成 + 20% E2E |
|
||
| **MVP/原型** | 关键路径 E2E | 少量核心测试即可 |
|
||
|
||
### 4.2 常用测试工具
|
||
|
||
| 工具 | 类型 | 适用场景 |
|
||
|------|------|----------|
|
||
| **Vitest** | 单元/集成 | Vite 项目首选,兼容 Jest API |
|
||
| **Jest** | 单元/集成 | Node.js 生态最流行 |
|
||
| **Playwright** | E2E | 跨浏览器,微软出品 |
|
||
| **Cypress** | E2E | 开发体验好,调试方便 |
|
||
| **Testing Library** | 组件测试 | 以用户视角测试 UI 组件 |
|
||
|
||
---
|
||
|
||
## 5. AI 助力:用大模型提升测试效率
|
||
|
||
大模型在测试领域的能力已经非常强大——它可以帮你生成测试用例、发现边界条件、甚至写出完整的测试代码。
|
||
|
||
### 5.1 生成单元测试
|
||
|
||
> **提示词**:
|
||
> ```
|
||
> 请为以下函数编写单元测试,使用 Vitest 框架,要求:
|
||
> 1. 遵循 AAA 模式(Arrange-Act-Assert)
|
||
> 2. 覆盖正常路径、边界条件和错误路径
|
||
> 3. 每个测试用例有清晰的中文描述
|
||
>
|
||
> [粘贴你的函数代码]
|
||
> ```
|
||
|
||
### 5.2 发现边界条件
|
||
|
||
> **提示词**:
|
||
> ```
|
||
> 分析以下函数,列出所有可能的边界条件和极端输入场景,
|
||
> 包括:空值、零、负数、超大数、特殊字符、并发情况等。
|
||
> 对每个场景说明预期行为和可能的风险。
|
||
>
|
||
> [粘贴你的函数代码]
|
||
> ```
|
||
|
||
### 5.3 从需求生成测试(TDD 辅助)
|
||
|
||
> **提示词**:
|
||
> ```
|
||
> 我要实现一个购物车模块,需求如下:
|
||
> - 添加商品、删除商品、修改数量
|
||
> - 自动计算总价(含折扣)
|
||
> - 库存不足时提示错误
|
||
>
|
||
> 请按照 TDD 思路,先写出测试用例(不写实现),
|
||
> 使用 Vitest,覆盖所有核心场景。
|
||
> ```
|
||
|
||
::: tip AI 使用建议
|
||
AI 生成的测试要检查断言是否有意义——避免 `expect(true).toBe(true)` 这种无效测试。好的测试应该在代码出错时真的能失败。
|
||
:::
|
||
|
||
---
|
||
|
||
## 6. 总结
|
||
|
||
1. **测试金字塔**:底层多、顶层少,平衡速度与真实度
|
||
2. **单元测试**:遵循 FIRST 原则和 AAA 模式,测试核心逻辑
|
||
3. **TDD**:红绿重构循环,用测试驱动设计
|
||
4. **策略选择**:根据项目类型和阶段,选择合适的测试比例
|
||
|
||
::: tip 终极思考
|
||
测试不是负担,而是**加速器**。短期看,写测试确实多花了时间;长期看,它节省了无数次手动验证、排查回归 Bug、以及深夜紧急修复的时间。好的测试让你有信心说出那句话:**"放心改,测试会告诉我们有没有问题。"**
|
||
:::
|
||
|
||
---
|
||
|
||
## 延伸阅读
|
||
|
||
- **经典书籍**:Kent Beck《测试驱动开发》是 TDD 的开山之作。
|
||
- **实用指南**:尝试用 Vitest 为一个小项目写测试,体验从零开始的测试流程。
|
||
- **测试模式**:了解 Mock、Stub、Spy 的区别和使用场景。
|
||
- **持续集成**:将测试集成到 CI/CD 流水线中,每次提交自动运行。
|