# 自动化测试指南

本项目包含完整的自动化测试套件，包括单元测试和端到端（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
```

祝测试愉快！🎉
