429 lines
9.2 KiB
Markdown
429 lines
9.2 KiB
Markdown
# 自动化测试指南
|
||
|
||
本项目包含完整的自动化测试套件,包括单元测试和端到端(E2E)测试。
|
||
|
||
## 📁 测试文件结构
|
||
|
||
```
|
||
backend/services/identity-service/
|
||
├── src/
|
||
│ ├── domain/
|
||
│ │ └── value-objects/
|
||
│ │ ├── mnemonic.vo.spec.ts # 助记词单元测试
|
||
│ │ └── phone-number.vo.spec.ts # 手机号单元测试
|
||
│ └── infrastructure/
|
||
│ └── external/
|
||
│ └── blockchain/
|
||
│ └── wallet-generator.service.spec.ts # 钱包生成服务测试
|
||
└── test/
|
||
├── app.e2e-spec.ts # 完整的 E2E 测试套件
|
||
└── jest-e2e.json # E2E 测试配置
|
||
```
|
||
|
||
## 🧪 测试类型
|
||
|
||
### 1. 单元测试(Unit Tests)
|
||
测试单个组件、类或函数的功能。
|
||
|
||
**位置**: 与源代码文件同目录,文件名以 `.spec.ts` 结尾
|
||
|
||
**已包含的单元测试**:
|
||
- ✅ `mnemonic.vo.spec.ts` - 助记词值对象测试
|
||
- ✅ `phone-number.vo.spec.ts` - 手机号值对象测试
|
||
- ✅ `wallet-generator.service.spec.ts` - 钱包生成服务测试
|
||
- ✅ `user-account.aggregate.spec.ts` - 用户账户聚合根测试(已存在)
|
||
|
||
### 2. 端到端测试(E2E Tests)
|
||
测试完整的用户场景和 API 端点。
|
||
|
||
**位置**: `test/` 目录
|
||
|
||
**已包含的 E2E 测试**:
|
||
- ✅ `app.e2e-spec.ts` - 完整的 API 测试套件(8个测试场景,40+测试用例)
|
||
|
||
## 🚀 运行测试
|
||
|
||
### 运行所有单元测试
|
||
```bash
|
||
npm test
|
||
```
|
||
|
||
### 运行单元测试(监听模式)
|
||
```bash
|
||
npm run test:watch
|
||
```
|
||
|
||
### 运行单元测试并生成覆盖率报告
|
||
```bash
|
||
npm run test:cov
|
||
```
|
||
|
||
### 运行 E2E 测试
|
||
```bash
|
||
npm run test:e2e
|
||
```
|
||
|
||
### 运行特定测试文件
|
||
```bash
|
||
# 运行助记词测试
|
||
npm test -- mnemonic.vo.spec
|
||
|
||
# 运行钱包生成服务测试
|
||
npm test -- wallet-generator.service.spec
|
||
|
||
# 运行手机号测试
|
||
npm test -- phone-number.vo.spec
|
||
```
|
||
|
||
### 调试测试
|
||
```bash
|
||
npm run test:debug
|
||
```
|
||
|
||
然后在 Chrome 中打开 `chrome://inspect`
|
||
|
||
## 📊 E2E 测试覆盖的场景
|
||
|
||
### 场景 1: 用户注册和账户创建
|
||
- ✅ 自动创建账户
|
||
- ✅ 验证钱包地址格式
|
||
- ✅ 参数验证
|
||
|
||
### 场景 2: 用户资料管理
|
||
- ✅ 获取个人资料
|
||
- ✅ 更新个人资料
|
||
- ✅ 认证验证
|
||
|
||
### 场景 3: 设备管理
|
||
- ✅ 获取设备列表
|
||
- ✅ 添加新设备
|
||
- ✅ 移除设备
|
||
- ✅ 设备数量限制(最多5个)
|
||
|
||
### 场景 4: Token 管理
|
||
- ✅ 刷新 Token
|
||
- ✅ Token 验证
|
||
- ✅ 无效 Token 拒绝
|
||
|
||
### 场景 5: 推荐系统
|
||
- ✅ 根据推荐码查询用户
|
||
- ✅ 使用推荐码注册
|
||
|
||
### 场景 6: KYC 认证
|
||
- ✅ 提交 KYC
|
||
- ✅ 身份证号验证
|
||
|
||
### 场景 7: 助记词恢复
|
||
- ✅ 正确助记词恢复
|
||
- ✅ 错误助记词拒绝
|
||
- ✅ 账户序列号验证
|
||
|
||
### 场景 8: 数据验证
|
||
- ✅ 手机号格式验证
|
||
- ✅ 各种边界条件测试
|
||
|
||
## 🎯 单元测试覆盖的功能
|
||
|
||
### Mnemonic 值对象测试
|
||
- ✅ 生成 12 个单词助记词
|
||
- ✅ 转换为 seed
|
||
- ✅ 验证助记词格式
|
||
- ✅ 助记词相等性比较
|
||
- ✅ 拒绝无效助记词
|
||
|
||
### PhoneNumber 值对象测试
|
||
- ✅ 验证有效的中国手机号
|
||
- ✅ 拒绝无效格式
|
||
- ✅ 手机号掩码(138****8000)
|
||
- ✅ 手机号相等性比较
|
||
|
||
### WalletGenerator 服务测试
|
||
- ✅ 生成完整钱包系统
|
||
- ✅ 三条链地址生成(KAVA/DST/BSC)
|
||
- ✅ 地址格式验证
|
||
- ✅ 助记词恢复
|
||
- ✅ 助记词验证
|
||
- ✅ 加密和解密
|
||
- ✅ 密钥派生
|
||
|
||
## 📈 查看测试覆盖率
|
||
|
||
运行覆盖率测试:
|
||
```bash
|
||
npm run test:cov
|
||
```
|
||
|
||
覆盖率报告会生成在 `coverage/` 目录:
|
||
```bash
|
||
# 在浏览器中查看 HTML 报告
|
||
open coverage/lcov-report/index.html # macOS
|
||
start coverage/lcov-report/index.html # Windows
|
||
```
|
||
|
||
## 🔧 测试配置
|
||
|
||
### 单元测试配置 (package.json)
|
||
```json
|
||
{
|
||
"jest": {
|
||
"moduleFileExtensions": ["js", "json", "ts"],
|
||
"rootDir": "src",
|
||
"testRegex": ".*\\.spec\\.ts$",
|
||
"transform": {
|
||
"^.+\\.(t|j)s$": "ts-jest"
|
||
},
|
||
"moduleNameMapper": {
|
||
"^@/(.*)$": "<rootDir>/$1"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### E2E 测试配置 (test/jest-e2e.json)
|
||
```json
|
||
{
|
||
"moduleFileExtensions": ["js", "json", "ts"],
|
||
"rootDir": ".",
|
||
"testEnvironment": "node",
|
||
"testRegex": ".e2e-spec.ts$",
|
||
"transform": {
|
||
"^.+\\.(t|j)s$": "ts-jest"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 🧩 编写新的测试
|
||
|
||
### 添加单元测试
|
||
|
||
在源文件同目录创建 `.spec.ts` 文件:
|
||
|
||
```typescript
|
||
// src/domain/value-objects/my-value.vo.spec.ts
|
||
import { MyValue } from './my-value.vo';
|
||
|
||
describe('MyValue', () => {
|
||
describe('create', () => {
|
||
it('should create valid value', () => {
|
||
const value = MyValue.create('test');
|
||
expect(value).toBeDefined();
|
||
});
|
||
});
|
||
});
|
||
```
|
||
|
||
### 添加 E2E 测试
|
||
|
||
在 `test/` 目录添加新的测试场景:
|
||
|
||
```typescript
|
||
// test/new-feature.e2e-spec.ts
|
||
import { Test, TestingModule } from '@nestjs/testing';
|
||
import { INestApplication } from '@nestjs/common';
|
||
import * as request from 'supertest';
|
||
import { AppModule } from '@/app.module';
|
||
|
||
describe('New Feature E2E Tests', () => {
|
||
let app: INestApplication;
|
||
|
||
beforeAll(async () => {
|
||
const moduleFixture: TestingModule = await Test.createTestingModule({
|
||
imports: [AppModule],
|
||
}).compile();
|
||
|
||
app = moduleFixture.createNestApplication();
|
||
await app.init();
|
||
});
|
||
|
||
afterAll(async () => {
|
||
await app.close();
|
||
});
|
||
|
||
it('should test new feature', async () => {
|
||
const response = await request(app.getHttpServer())
|
||
.get('/api/v1/new-endpoint')
|
||
.expect(200);
|
||
|
||
expect(response.body).toBeDefined();
|
||
});
|
||
});
|
||
```
|
||
|
||
## 🎬 CI/CD 集成
|
||
|
||
### GitHub Actions 示例
|
||
|
||
创建 `.github/workflows/test.yml`:
|
||
|
||
```yaml
|
||
name: Tests
|
||
|
||
on: [push, pull_request]
|
||
|
||
jobs:
|
||
test:
|
||
runs-on: ubuntu-latest
|
||
|
||
services:
|
||
postgres:
|
||
image: postgres:16
|
||
env:
|
||
POSTGRES_PASSWORD: postgres
|
||
options: >-
|
||
--health-cmd pg_isready
|
||
--health-interval 10s
|
||
--health-timeout 5s
|
||
--health-retries 5
|
||
|
||
steps:
|
||
- uses: actions/checkout@v3
|
||
|
||
- name: Setup Node.js
|
||
uses: actions/setup-node@v3
|
||
with:
|
||
node-version: '20'
|
||
|
||
- name: Install dependencies
|
||
run: npm ci
|
||
|
||
- name: Generate Prisma Client
|
||
run: npm run prisma:generate
|
||
|
||
- name: Run unit tests
|
||
run: npm test
|
||
|
||
- name: Run E2E tests
|
||
run: npm run test:e2e
|
||
env:
|
||
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
|
||
|
||
- name: Upload coverage
|
||
uses: codecov/codecov-action@v3
|
||
```
|
||
|
||
## 📋 测试最佳实践
|
||
|
||
### 1. 测试命名
|
||
使用清晰的描述性名称:
|
||
```typescript
|
||
// ✅ 好的命名
|
||
it('应该拒绝无效的手机号格式', () => {});
|
||
|
||
// ❌ 不好的命名
|
||
it('test1', () => {});
|
||
```
|
||
|
||
### 2. AAA 模式
|
||
遵循 Arrange-Act-Assert 模式:
|
||
```typescript
|
||
it('应该创建用户', () => {
|
||
// Arrange - 准备测试数据
|
||
const userData = { name: 'Test' };
|
||
|
||
// Act - 执行操作
|
||
const user = createUser(userData);
|
||
|
||
// Assert - 验证结果
|
||
expect(user.name).toBe('Test');
|
||
});
|
||
```
|
||
|
||
### 3. 独立性
|
||
每个测试应该独立运行:
|
||
```typescript
|
||
// ✅ 好的做法
|
||
beforeEach(() => {
|
||
// 为每个测试准备新的数据
|
||
testData = createFreshData();
|
||
});
|
||
|
||
// ❌ 不好的做法
|
||
let sharedData;
|
||
it('test1', () => {
|
||
sharedData = modify(sharedData); // 影响其他测试
|
||
});
|
||
```
|
||
|
||
### 4. 清理
|
||
在测试后清理资源:
|
||
```typescript
|
||
afterEach(async () => {
|
||
await cleanupTestData();
|
||
});
|
||
|
||
afterAll(async () => {
|
||
await app.close();
|
||
});
|
||
```
|
||
|
||
## 🐛 调试失败的测试
|
||
|
||
### 1. 查看详细输出
|
||
```bash
|
||
npm test -- --verbose
|
||
```
|
||
|
||
### 2. 运行单个测试
|
||
```bash
|
||
npm test -- --testNamePattern="应该创建用户"
|
||
```
|
||
|
||
### 3. 使用 console.log
|
||
```typescript
|
||
it('debug test', () => {
|
||
const result = someFunction();
|
||
console.log('Result:', result); // 调试输出
|
||
expect(result).toBe(expected);
|
||
});
|
||
```
|
||
|
||
### 4. 使用 Node 调试器
|
||
```bash
|
||
npm run test:debug
|
||
```
|
||
|
||
在 Chrome 打开 `chrome://inspect`,点击 "inspect"
|
||
|
||
## 📚 相关资源
|
||
|
||
- [Jest 文档](https://jestjs.io/docs/getting-started)
|
||
- [NestJS 测试文档](https://docs.nestjs.com/fundamentals/testing)
|
||
- [Supertest 文档](https://github.com/visionmedia/supertest)
|
||
- [测试驱动开发 (TDD)](https://martinfowler.com/bliki/TestDrivenDevelopment.html)
|
||
|
||
## 🎯 测试目标
|
||
|
||
### 当前覆盖率目标
|
||
- 单元测试覆盖率:> 80%
|
||
- E2E 测试覆盖率:> 70%
|
||
- 关键路径覆盖率:100%
|
||
|
||
### 持续改进
|
||
- 为新功能添加测试
|
||
- 为 bug 修复添加回归测试
|
||
- 定期审查和更新测试
|
||
- 移除过时的测试
|
||
|
||
---
|
||
|
||
## 🚀 快速开始
|
||
|
||
```bash
|
||
# 1. 安装依赖
|
||
npm install
|
||
|
||
# 2. 安装 supertest(E2E 测试依赖)
|
||
npm install --save-dev supertest @types/supertest
|
||
|
||
# 3. 运行所有测试
|
||
npm test
|
||
|
||
# 4. 运行 E2E 测试
|
||
npm run test:e2e
|
||
|
||
# 5. 查看覆盖率
|
||
npm run test:cov
|
||
```
|
||
|
||
祝测试愉快!🎉
|