diff --git a/backend/services/identity-service/.env.test b/backend/services/identity-service/.env.test new file mode 100644 index 00000000..a7c9a1c2 --- /dev/null +++ b/backend/services/identity-service/.env.test @@ -0,0 +1,31 @@ +# Test Environment Configuration + +# Database - 使用测试数据库 +DATABASE_URL="postgresql://postgres:password@localhost:5432/rwa_identity_test?schema=public" + +# JWT +JWT_SECRET="test-jwt-secret-key-for-e2e-tests" +JWT_ACCESS_EXPIRES_IN="2h" +JWT_REFRESH_EXPIRES_IN="30d" + +# Redis +REDIS_HOST="localhost" +REDIS_PORT=6379 +REDIS_PASSWORD="" +REDIS_DB=1 + +# Kafka - 测试环境 +KAFKA_BROKERS="localhost:9092" +KAFKA_CLIENT_ID="identity-service-test" +KAFKA_GROUP_ID="identity-service-test-group" + +# SMS Service - 可以使用mock +SMS_API_URL="https://sms-api.example.com" +SMS_API_KEY="test-sms-api-key" + +# App +APP_PORT=3001 +APP_ENV="test" + +# Blockchain Encryption +WALLET_ENCRYPTION_SALT="test-wallet-salt" diff --git a/backend/services/identity-service/AUTOMATED_TESTS_README.md b/backend/services/identity-service/AUTOMATED_TESTS_README.md index c34876b4..04b90888 100644 --- a/backend/services/identity-service/AUTOMATED_TESTS_README.md +++ b/backend/services/identity-service/AUTOMATED_TESTS_README.md @@ -45,7 +45,20 @@ npm install - `supertest@^6.3.3` - HTTP 断言库 - `@types/supertest@^6.0.0` - TypeScript 类型定义 -### 2. 运行所有单元测试 +### 2. 准备 E2E 测试环境 + +E2E 测试需要数据库和 Redis,但 **不需要** Kafka(已使用 Mock)。 + +详细设置请参阅: [E2E_TEST_SETUP.md](E2E_TEST_SETUP.md) + +快速开始: +```bash +# 确保 PostgreSQL 和 Redis 正在运行 +# 准备测试数据库 +DATABASE_URL="postgresql://postgres:password@localhost:5432/rwa_identity_test?schema=public" npx prisma migrate dev +``` + +### 3. 运行所有单元测试 ```bash npm test ``` @@ -60,11 +73,17 @@ Test Suites: 3 passed, 3 total Tests: 30+ passed, 30+ total ``` -### 3. 运行 E2E 测试 +### 4. 运行 E2E 测试 ```bash npm run test:e2e ``` +**注意**: E2E 测试需要: +- ✅ PostgreSQL 数据库(测试数据库) +- ✅ Redis 服务 +- ❌ **不需要** Kafka(已使用 Mock) +- ❌ **不需要** SMS 服务(已使用 Mock) + **预期输出**: ``` PASS test/app.e2e-spec.ts @@ -76,9 +95,11 @@ PASS test/app.e2e-spec.ts ... Test Suites: 1 passed, 1 total -Tests: 40+ passed, 40+ total +Tests: 20+ passed, 20+ total ``` +如果遇到问题,请参阅 [E2E_TEST_SETUP.md](E2E_TEST_SETUP.md) + ### 4. 查看测试覆盖率 ```bash npm run test:cov diff --git a/backend/services/identity-service/E2E_TEST_SETUP.md b/backend/services/identity-service/E2E_TEST_SETUP.md new file mode 100644 index 00000000..e9b702d8 --- /dev/null +++ b/backend/services/identity-service/E2E_TEST_SETUP.md @@ -0,0 +1,201 @@ +# E2E 测试设置指南 + +## 前置条件 + +E2E测试需要以下服务运行: + +### 1. PostgreSQL 数据库 + +测试使用独立的测试数据库,不会影响开发数据库。 + +```bash +# 确保 PostgreSQL 正在运行 +# 创建测试数据库(如果还没有) +createdb rwa_identity_test + +# 或使用 psql +psql -U postgres +CREATE DATABASE rwa_identity_test; +``` + +### 2. Redis (可选) + +测试需要 Redis 用于 Token 管理。 + +```bash +# 启动 Redis(如果还没运行) +redis-server + +# 或使用 Docker +docker run -d -p 6379:6379 redis:latest +``` + +### 3. 配置测试环境变量 + +已创建 `.env.test` 文件,包含测试环境配置: + +```env +DATABASE_URL="postgresql://postgres:password@localhost:5432/rwa_identity_test?schema=public" +REDIS_HOST="localhost" +REDIS_PORT=6379 +JWT_SECRET="test-jwt-secret-key-for-e2e-tests" +WALLET_ENCRYPTION_SALT="test-wallet-salt" +``` + +**重要**: 请根据你的本地环境修改数据库连接字符串中的用户名和密码。 + +## 运行测试步骤 + +### 1. 准备测试数据库 + +```bash +# 生成 Prisma Client +npm run prisma:generate + +# 运行数据库迁移(针对测试数据库) +DATABASE_URL="postgresql://postgres:password@localhost:5432/rwa_identity_test?schema=public" npx prisma migrate dev +``` + +### 2. 运行 E2E 测试 + +```bash +# 设置环境变量并运行测试 +NODE_ENV=test npm run test:e2e +``` + +### 3. 清理测试数据(可选) + +E2E测试会在测试数据库中创建数据。如果需要清理: + +```bash +# 重置测试数据库 +DATABASE_URL="postgresql://postgres:password@localhost:5432/rwa_identity_test?schema=public" npx prisma migrate reset --skip-seed +``` + +## Mock 服务说明 + +E2E 测试已经配置了以下 Mock 服务,**不需要**真实的外部服务: + +### ✅ Kafka (已 Mock) +- `EventPublisherService` 已被 mock +- 不需要运行 Kafka 服务器 +- 事件发布操作会被记录但不会真实发送 + +### ✅ SMS 服务 (已 Mock) +- `SmsService` 已被 mock +- 不需要真实的 SMS API +- 验证码发送操作会自动成功 + +### ⚠️ 仍需要真实服务 + +- **PostgreSQL** - 需要真实数据库来测试数据持久化 +- **Redis** - 需要真实 Redis 来测试 Token 缓存 + +## 常见问题 + +### 问题 1: 数据库连接失败 + +``` +Error: Can't reach database server +``` + +**解决方案**: +1. 确认 PostgreSQL 正在运行 +2. 检查 `.env.test` 中的数据库连接字符串 +3. 确认测试数据库已创建 + +### 问题 2: Redis 连接失败 + +``` +Error: connect ECONNREFUSED 127.0.0.1:6379 +``` + +**解决方案**: +1. 启动 Redis: `redis-server` +2. 或临时禁用 Redis(需要修改代码) + +### 问题 3: Kafka 警告信息 + +``` +KafkaJS v2.0.0 switched default partitioner +``` + +**说明**: 这只是警告,不影响测试运行。Kafka 已被 mock,不会真实连接。 + +可以设置环境变量禁用警告: + +```bash +KAFKAJS_NO_PARTITIONER_WARNING=1 npm run test:e2e +``` + +### 问题 4: 测试超时 + +``` +Timeout - Async callback was not invoked within the 5000 ms timeout +``` + +**解决方案**: +- 确保数据库和 Redis 响应速度正常 +- 增加 Jest 超时时间(在 jest-e2e.json 中配置) + +## 测试覆盖范围 + +E2E 测试覆盖了以下功能: + +1. ✅ 用户注册和账户创建 +2. ✅ 用户资料管理 +3. ✅ 设备管理(添加/删除/限制) +4. ✅ Token 刷新 +5. ✅ 推荐系统 +6. ✅ KYC 认证 +7. ✅ 助记词恢复 +8. ✅ 数据验证 + +总计: **20+ 个测试用例** + +## 快速开始(一键命令) + +如果你的环境已经配置好 PostgreSQL 和 Redis: + +```bash +# 1. 准备测试数据库 +DATABASE_URL="postgresql://postgres:password@localhost:5432/rwa_identity_test?schema=public" npx prisma migrate dev + +# 2. 运行测试 +npm run test:e2e + +# 3. 查看测试结果 +# 所有测试通过后,你会看到类似输出: +# Test Suites: 1 passed, 1 total +# Tests: 20 passed, 20 total +``` + +## Docker 环境快速启动 + +如果你想使用 Docker 运行依赖服务: + +```bash +# 启动 PostgreSQL 和 Redis +docker-compose -f docker-compose.test.yml up -d + +# 等待服务启动 +sleep 5 + +# 运行测试 +npm run test:e2e + +# 停止服务 +docker-compose -f docker-compose.test.yml down +``` + +## 注意事项 + +1. **测试数据隔离**: 测试使用独立的测试数据库,不会影响开发环境 +2. **Mock 服务**: Kafka 和 SMS 已被 mock,测试速度更快 +3. **数据清理**: 每次测试运行可能会在数据库中留下数据,定期清理测试数据库 +4. **并发问题**: 避免同时运行多个测试实例,可能导致数据冲突 + +## 下一步 + +- 查看 [AUTOMATED_TESTS_README.md](AUTOMATED_TESTS_README.md) 了解完整的测试体系 +- 查看 [TEST_AUTOMATION_GUIDE.md](TEST_AUTOMATION_GUIDE.md) 了解如何编写新测试 diff --git a/backend/services/identity-service/test/app.e2e-spec.ts b/backend/services/identity-service/test/app.e2e-spec.ts index b8cc2c69..3f4e0079 100644 --- a/backend/services/identity-service/test/app.e2e-spec.ts +++ b/backend/services/identity-service/test/app.e2e-spec.ts @@ -3,6 +3,8 @@ import { INestApplication, ValidationPipe } from '@nestjs/common'; import * as request from 'supertest'; import { AppModule } from '@/app.module'; import { PrismaService } from '@/infrastructure/persistence/prisma/prisma.service'; +import { EventPublisherService } from '@/infrastructure/kafka/event-publisher.service'; +import { SmsService } from '@/infrastructure/external/sms/sms.service'; describe('Identity Service E2E Tests', () => { let app: INestApplication; @@ -14,10 +16,28 @@ describe('Identity Service E2E Tests', () => { let referralCode: string; let deviceId: string; + // Mock Kafka Event Publisher - 避免真实Kafka连接 + const mockEventPublisher = { + publish: jest.fn().mockResolvedValue(undefined), + publishAll: jest.fn().mockResolvedValue(undefined), + onModuleInit: jest.fn().mockResolvedValue(undefined), + onModuleDestroy: jest.fn().mockResolvedValue(undefined), + }; + + // Mock SMS Service - 避免真实SMS API调用 + const mockSmsService = { + sendVerificationCode: jest.fn().mockResolvedValue(true), + }; + beforeAll(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [AppModule], - }).compile(); + }) + .overrideProvider(EventPublisherService) + .useValue(mockEventPublisher) + .overrideProvider(SmsService) + .useValue(mockSmsService) + .compile(); app = moduleFixture.createNestApplication(); @@ -56,9 +76,15 @@ describe('Identity Service E2E Tests', () => { deviceName: 'Test Device', provinceCode: '110000', cityCode: '110100', - }) - .expect(201); + }); + // 打印错误信息以便调试 + if (response.status !== 201) { + console.error('Response status:', response.status); + console.error('Response body:', JSON.stringify(response.body, null, 2)); + } + + expect(response.status).toBe(201); expect(response.body.success).toBe(true); expect(response.body.data).toHaveProperty('userId'); expect(response.body.data).toHaveProperty('accountSequence');