# 步骤5：测试覆盖检查

## 🎯 检查目标
检查测试文件的完整性和覆盖率，确保严格的一对一测试映射和测试分离。

## 📋 测试文件存在性检查

### 需要测试文件的类型
```typescript
✅ 必须有测试文件：
- *.service.ts        # Service类 - 业务逻辑类
- *.controller.ts     # Controller类 - 控制器类
- *.gateway.ts        # Gateway类 - WebSocket网关类
- *.guard.ts          # Guard类 - 守卫类（游戏服务器安全重要）
- *.interceptor.ts    # Interceptor类 - 拦截器类（日志监控重要）
- *.middleware.ts     # Middleware类 - 中间件类（性能监控重要）

❌ 不需要测试文件：
- *.dto.ts           # DTO类 - 数据传输对象
- *.interface.ts     # Interface文件 - 接口定义
- *.constants.ts     # Constants文件 - 常量定义
- *.config.ts        # Config文件 - 配置文件
- *.utils.ts         # 简单Utils工具类（复杂工具类需要）
```

### 测试文件命名规范
```typescript
✅ 正确的一对一映射：
src/business/auth/auth.service.ts
src/business/auth/auth.service.spec.ts

src/core/location_broadcast_core/location_broadcast_core.service.ts
src/core/location_broadcast_core/location_broadcast_core.service.spec.ts

src/business/admin/admin.gateway.ts
src/business/admin/admin.gateway.spec.ts

❌ 错误的命名：
src/business/auth/auth_services.spec.ts     # 测试多个service，违反一对一原则
src/business/auth/auth_test.spec.ts         # 命名不对应
```

## 🔥 严格一对一测试映射（重要）

### 强制要求
- **严格对应**：每个测试文件必须严格对应一个源文件
- **禁止多对一**：不允许一个测试文件测试多个源文件
- **禁止一对多**：不允许一个源文件的测试分散在多个测试文件
- **命名对应**：测试文件名必须与源文件名完全对应（除.spec.ts后缀外）

### 测试范围严格限制
```typescript
// ✅ 正确：只测试LoginService的功能
// 文件：src/business/auth/login.service.spec.ts
describe('LoginService', () => {
  describe('validateUser', () => {
    it('should validate user credentials', () => {
      // 只测试LoginService.validateUser方法
      // 使用Mock隔离UserRepository等外部依赖
    });
    
    it('should throw error for invalid credentials', () => {
      // 测试异常情况
    });
  });
  
  describe('generateToken', () => {
    it('should generate valid JWT token', () => {
      // 只测试LoginService.generateToken方法
    });
  });
});

// ❌ 错误：在LoginService测试中测试其他服务
describe('LoginService', () => {
  it('should integrate with UserRepository', () => {
    // 错误：这是集成测试，应该移到test/integration/
  });
  
  it('should work with EmailService', () => {
    // 错误：测试了EmailService的功能，违反范围限制
  });
});
```

## 🏗️ 测试分离架构（强制要求）

### 顶层test目录结构
```
test/
├── integration/          # 集成测试 - 测试多个模块间的交互
│   ├── auth_integration.spec.ts
│   ├── location_broadcast_integration.spec.ts
│   └── zulip_integration.spec.ts
├── e2e/                 # 端到端测试 - 完整业务流程测试
│   ├── user_registration_e2e.spec.ts
│   ├── location_broadcast_e2e.spec.ts
│   └── admin_operations_e2e.spec.ts
├── performance/         # 性能测试 - WebSocket和高并发测试
│   ├── websocket_performance.spec.ts
│   ├── database_performance.spec.ts
│   └── memory_usage.spec.ts
├── property/           # 属性测试 - 基于属性的随机测试
│   ├── admin_property.spec.ts
│   ├── user_validation_property.spec.ts
│   └── position_update_property.spec.ts
└── fixtures/           # 测试数据和工具
    ├── test_data.ts
    └── test_helpers.ts
```

### 测试类型分离要求
```typescript
// ✅ 正确：单元测试只在源文件同目录
// 文件位置：src/business/auth/login.service.spec.ts
describe('LoginService Unit Tests', () => {
  // 只测试LoginService的单个方法功能
  // 使用Mock隔离所有外部依赖
});

// ✅ 正确：集成测试统一在test/integration/
// 文件位置：test/integration/auth_integration.spec.ts
describe('Auth Integration Tests', () => {
  it('should integrate LoginService with UserRepository and TokenService', () => {
    // 测试多个模块间的真实交互
  });
});

// ✅ 正确：E2E测试统一在test/e2e/
// 文件位置：test/e2e/user_auth_e2e.spec.ts
describe('User Authentication E2E Tests', () => {
  it('should handle complete user login flow', () => {
    // 端到端完整业务流程测试
  });
});
```

## 🎮 游戏服务器特殊测试要求

### WebSocket Gateway测试
```typescript
// ✅ 正确：完整的WebSocket测试
// 文件：src/business/location/location_broadcast.gateway.spec.ts
describe('LocationBroadcastGateway', () => {
  let gateway: LocationBroadcastGateway;
  let mockServer: jest.Mocked<Server>;

  beforeEach(async () => {
    // 设置Mock服务器和依赖
  });

  describe('handleConnection', () => {
    it('should accept valid WebSocket connection with JWT token', () => {
      // 正常连接测试
    });
    
    it('should reject connection with invalid JWT token', () => {
      // 异常连接测试
    });
    
    it('should handle connection when room is at capacity limit', () => {
      // 边界情况测试
    });
  });

  describe('handlePositionUpdate', () => {
    it('should broadcast position to all room members', () => {
      // 实时通信测试
    });
    
    it('should validate position data format', () => {
      // 数据验证测试
    });
  });

  describe('handleDisconnect', () => {
    it('should clean up user resources on disconnect', () => {
      // 断开连接测试
    });
  });
});
```

### 双模式服务测试
```typescript
// ✅ 正确：内存服务测试
// 文件：src/core/users/users_memory.service.spec.ts
describe('UsersMemoryService', () => {
  it('should create user in memory storage', () => {
    // 测试内存模式特定功能
  });
  
  it('should handle concurrent access correctly', () => {
    // 测试内存模式并发处理
  });
});

// ✅ 正确：数据库服务测试
// 文件：src/core/users/users_database.service.spec.ts
describe('UsersDatabaseService', () => {
  it('should create user in database', () => {
    // 测试数据库模式特定功能
  });
  
  it('should handle database transaction correctly', () => {
    // 测试数据库事务处理
  });
});

// ✅ 正确：双模式一致性测试（集成测试）
// 文件：test/integration/users_dual_mode_integration.spec.ts
describe('Users Dual Mode Integration', () => {
  it('should have identical behavior for user creation', () => {
    // 测试两种模式行为一致性
  });
});
```

### 属性测试（管理员模块）
```typescript
// ✅ 正确：属性测试
// 文件：test/property/admin_property.spec.ts
import * as fc from 'fast-check';

describe('AdminService Properties', () => {
  it('should handle any valid user status update', () => {
    fc.assert(fc.property(
      fc.integer({ min: 1, max: 1000000 }), // userId
      fc.constantFrom(...Object.values(UserStatus)), // status
      async (userId, status) => {
        try {
          const result = await adminService.updateUserStatus(userId, status);
          expect(result).toBeDefined();
          expect(result.status).toBe(status);
        } catch (error) {
          expect(error).toBeInstanceOf(NotFoundException || BadRequestException);
        }
      }
    ));
  });
});
```

## 📍 测试文件位置规范

### 正确位置
```
✅ 正确：测试文件与源文件同目录
src/business/auth/
├── auth.service.ts
├── auth.service.spec.ts      # 单元测试
├── auth.controller.ts
└── auth.controller.spec.ts   # 单元测试

src/core/location_broadcast_core/
├── location_broadcast_core.service.ts
└── location_broadcast_core.service.spec.ts
```

### 错误位置（必须修正）
```
❌ 错误：测试文件在单独文件夹
src/business/auth/
├── auth.service.ts
├── auth.controller.ts
└── tests/                    # 错误：单独的测试文件夹
    ├── auth.service.spec.ts  # 应该移到上级目录
    └── auth.controller.spec.ts

src/business/auth/
├── auth.service.ts
├── auth.controller.ts
└── __tests__/               # 错误：单独的测试文件夹
    └── auth.spec.ts         # 应该拆分并移到上级目录
```

## 🧪 测试执行验证（强制要求）

### 测试命令执行
```bash
# 单元测试（严格限制：只执行.spec.ts文件）
npm run test:unit
# 等价于: jest --testPathPattern=spec.ts --testPathIgnorePatterns="integration|e2e|performance|property"

# 集成测试（统一在test/integration/目录执行）
npm run test:integration
# 等价于: jest test/integration/

# E2E测试（统一在test/e2e/目录执行）
npm run test:e2e
# 等价于: jest test/e2e/

# 属性测试（统一在test/property/目录执行）
npm run test:property
# 等价于: jest test/property/

# 性能测试（统一在test/performance/目录执行）
npm run test:performance
# 等价于: jest test/performance/
```

### 测试执行顺序
1. **第一阶段**：单元测试（快速反馈）
2. **第二阶段**：集成测试（模块协作）
3. **第三阶段**：E2E测试（业务流程）
4. **第四阶段**：性能测试（系统性能）

## 🔍 检查执行步骤

1. **扫描需要测试的文件类型**
   - 识别所有.service.ts、.controller.ts、.gateway.ts等文件
   - 检查是否有对应的.spec.ts测试文件

2. **验证一对一测试映射**
   - 确保每个测试文件严格对应一个源文件
   - 检查测试文件命名是否正确对应

3. **检查测试范围限制**
   - 确保测试内容严格限于对应源文件功能
   - 识别跨文件测试和混合测试

4. **检查测试文件位置**
   - 确保单元测试与源文件在同一目录
   - 识别需要扁平化的测试文件夹

5. **分离集成测试和E2E测试**
   - 将集成测试移动到test/integration/
   - 将E2E测试移动到test/e2e/
   - 将性能测试移动到test/performance/
   - 将属性测试移动到test/property/

6. **执行测试验证**
   - 运行单元测试命令验证通过
   - 确保测试覆盖率达标
   - 验证测试质量和有效性

7. **游戏服务器特殊检查**
   - WebSocket Gateway的完整测试覆盖
   - 双模式服务的一致性测试
   - 属性测试的正确实现

## 🔥 重要提醒

**如果在本步骤中执行了任何修改操作（创建测试文件、移动测试文件、修正测试内容等），必须立即重新执行步骤5的完整检查！**

- ✅ 执行修改 → 🔥 立即重新执行步骤5 → 提供验证报告 → 等待用户确认
- ❌ 执行修改 → 直接进入步骤6（错误做法）

**不能跳过重新检查环节！**