# 测试规范

## 规则（Rules）

# 测试规范 - 规范

## 测试金字塔覆盖要求

| 层级 | 数量占比 | 运行速度 | 覆盖内容 |
|:-----|:---------|:---------|:---------|
| 单元测试 | 70% | 毫秒级 | 函数/模块/组件 |
| 集成测试 | 20% | 秒级 | 接口/组件交互 |
| E2E 测试 | 10% | 分钟级 | 核心用户流程 |

## 覆盖率要求

| 指标 | 目标值 |
|:-----|:-------|
| Statements | ≥ 80% |
| Branches | ≥ 75% |
| Functions | ≥ 80% |
| Lines | ≥ 80% |

## 文件命名规范
- `{module}.test.js` — Jest 默认
- `{module}.spec.js` — Mocha 风格
- `__tests__/{module}.test.js` — 集中存放

## 必须测试的场景
1. **正常路径**：输入合法参数，期望成功返回
2. **边界值**：空值、极值、超长输入
3. **错误路径**：参数错误、权限不足、资源不存在
4. **异常状态**：超时、网络错误、服务不可用

## 禁止行为
- ❌ 禁止测试依赖数据库/文件系统中的真实数据
- ❌ 禁止测试之间共享状态
- ❌ 禁止编写只测正常路径的"快乐路径测试"
- ❌ 禁止使用 `sleep/timer` 等待异步操作
- ❌ 禁止提交只跳过（skip）不修复的测试

## 方法（Methods）

# 测试规范 - 方法

## 前置条件
- [ ] 已确定测试范围（单元/集成/E2E）
- [ ] 已安装测试框架（Jest / Mocha / Cypress）

## 流程概览
```
分析被测代码 → 编写测试用例（AAA模式） → 运行测试 → 检查覆盖率 → 补充用例
```

## 单元测试（AAA 模式）

### Arrange - 准备
```javascript
const input = { name: '张三', email: 'test@example.com' };
```

### Act - 执行
```javascript
const result = await userService.createUser(input);
```

### Assert - 断言
```javascript
expect(result).toHaveProperty('id');
expect(result.name).toBe('张三');
```

### 完整示例
```javascript
describe('UserService', () => {
  describe('createUser()', () => {
    it('应该成功创建用户并返回用户信息', async () => {
      const input = { name: '张三', email: 'test@example.com' };
      const result = await userService.createUser(input);
      expect(result).toHaveProperty('id');
      expect(result.name).toBe('张三');
    });

    it('当邮箱已存在时应该抛出错误', async () => {
      const input = { name: '李四', email: 'exist@example.com' };
      await expect(userService.createUser(input)).rejects.toThrow('邮箱已存在');
    });
  });
});
```

## 集成测试
```javascript
describe('POST /api/v1/users', () => {
  it('应该创建用户并返回 201', async () => {
    const res = await request(app)
      .post('/api/v1/users')
      .send({ name: '张三', email: 'test@example.com' })
      .set('Authorization', `Bearer ${token}`);

    expect(res.status).toBe(201);
    expect(res.body.code).toBe(0);
  });
});
```

## Mock 规范
- 单元测试：Mock 所有外部依赖（DB、API、文件系统）
- 集成测试：Mock 第三方外部服务
- Mock 数据使用工厂函数（Factory）生成

## 技巧（Tips）

# 测试规范 - 技巧

## 1. 先写测试再写代码（TDD）
红 → 绿 → 重构，确保代码可测试性。

## 2. 测试描述用中文
```javascript
// ✅ 好的描述
it('当邮箱为空时应该抛出参数错误', ...);

// ❌ 模糊的描述
it('should work', ...);
```

## 3. 使用 describe 分层组织
```javascript
describe('模块名', () => {
  describe('方法名', () => {
    describe('特定场景', () => {
      it('期望结果', ...);
    });
  });
});
```

## 4. 常用 Matcher 速查
```javascript
expect(a).toBe(value);           // 严格相等
expect(a).toEqual(obj);          // 深度相等
expect(a).toHaveProperty(key);   // 包含属性
expect(fn).toThrow(msg);         // 抛出异常
expect(arr).toContain(item);     // 包含元素
expect(mock).toHaveBeenCalled(); // 被调用过
```
