refactor(docs): reorganize documentation directory structure
- Create user/ - User guides and configuration documentation - Create features/ - Feature specifications and business flows - Create debugging/ - Debug guides and quick references - Create testing/ - Test infrastructure, reports, and plans - Create internal/ - Internal plans, analyses, and templates - Move cleaner/*.md to cleaner/ directory - Move LOGGING_*.md to developer/guides/ Add docs/README.md as documentation index with category navigation and quick lookup guide. The reorganized structure makes it easier for users and developers to quickly locate relevant documentation.
This commit is contained in:
654
docs/testing/TEST_REVIEW_REPORT.md
Normal file
654
docs/testing/TEST_REVIEW_REPORT.md
Normal file
@@ -0,0 +1,654 @@
|
||||
# ERPAuto 测试实现审查报告
|
||||
|
||||
**审查日期**: 2026 年 4 月 4 日
|
||||
**审查范围**: 单元测试、集成测试、E2E 测试
|
||||
**审查人**: Sisyphus AI Agent
|
||||
|
||||
---
|
||||
|
||||
## 📊 执行摘要
|
||||
|
||||
### 测试架构概览
|
||||
|
||||
| 维度 | 详情 |
|
||||
| ---------------- | ---------------------------------------------- |
|
||||
| **测试框架** | Vitest 4.0.18 + Playwright Test 1.58.2 |
|
||||
| **测试文件总数** | 44 个 (31 单元 + 7 集成 + 3 E2E + 3 调试/手动) |
|
||||
| **测试用例总数** | ~300 个 |
|
||||
| **当前通过率** | ~67% (约 200 通过 / 48 失败) |
|
||||
| **测试覆盖率** | 未配置阈值 |
|
||||
|
||||
### 测试结果摘要
|
||||
|
||||
```
|
||||
✅ 通过测试:~200 个
|
||||
❌ 失败套件:20 个
|
||||
❌ 失败用例:28 个
|
||||
⚠️ 空测试文件:17 个
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 测试文件组织
|
||||
|
||||
```
|
||||
tests/
|
||||
├── setup.ts # 全局 Setup (Electron Mock)
|
||||
├── fixtures/
|
||||
│ ├── create-fixtures.ts # Excel 测试数据生成器
|
||||
│ ├── test-export.xlsx # 生成的测试数据
|
||||
│ └── test-empty-orders.xlsx # 空数据夹具
|
||||
├── unit/ # 31 个单元测试文件
|
||||
│ ├── services/
|
||||
│ │ ├── erp/ # ERP 服务测试
|
||||
│ │ │ ├── page-diagnostics.test.ts
|
||||
│ │ │ └── erp-error-context.test.ts
|
||||
│ │ └── logger/
|
||||
│ │ └── error-utils.test.ts # ✅ 优秀测试示例
|
||||
│ ├── errors.test.ts # ✅ 错误类型测试
|
||||
│ ├── request-context.test.ts # ✅ 请求上下文测试 (432 行)
|
||||
│ ├── schemas.test.ts # ✅ Zod Schema 验证
|
||||
│ ├── repositories.test.ts # ❌ 数据库 Repository 测试 (失败)
|
||||
│ ├── mysql.test.ts # ❌ MySQL 单元测试 (失败)
|
||||
│ ├── sql-server.test.ts # ❌ SQL Server 测试 (失败)
|
||||
│ ├── extractor.test.ts # ❌ 提取器测试 (失败)
|
||||
│ ├── cleaner*.test.ts # ❌ 清理器测试 (3 个文件,失败)
|
||||
│ ├── update-*.test.ts # ❌ 更新服务测试 (5 个文件,部分失败)
|
||||
│ ├── logger*.test.ts # ❌ Logger 测试 (3 个文件,部分失败)
|
||||
│ ├── auth-handler.test.ts # ✅ IPC Handler 测试
|
||||
│ ├── excel-parser.test.ts # ❌ Excel 解析测试 (失败)
|
||||
│ ├── use-*.test.ts # ✅ React Hooks 测试 (2 个文件)
|
||||
│ └── ... # 其他服务测试
|
||||
├── integration/ # 7 个集成测试文件
|
||||
│ ├── cleaner.test.ts # ❌ 真实 ERP 集成 (0 测试)
|
||||
│ ├── extractor.test.ts # ❌ 提取器集成 (0 测试)
|
||||
│ ├── erp-auth.test.ts # ❌ 认证集成 (0 测试)
|
||||
│ ├── mysql.test.ts # ❌ MySQL 集成 (0 测试)
|
||||
│ ├── sql-server.test.ts # ❌ SQL Server 集成 (0 测试)
|
||||
│ ├── ipc-logging.test.ts # ❌ IPC 日志集成 (0 测试)
|
||||
│ └── logger-performance.test.ts # ✅ 日志性能测试 (24 测试)
|
||||
├── e2e/ # 3 个 E2E 测试文件
|
||||
│ ├── auth-flow.test.ts # 登录/登出流程
|
||||
│ ├── dialog-focus.test.ts # 对话框焦点管理
|
||||
│ └── extractor-workflow.test.ts # 完整提取工作流
|
||||
├── debug/ # 调试测试
|
||||
│ └── env.test.ts # 环境变量测试 (1 失败)
|
||||
└── manual/ # 手动测试脚本
|
||||
├── excel-parser-test.ts # Excel 解析手动测试
|
||||
└── ... # 临时调试脚本
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 关键问题诊断
|
||||
|
||||
### P0 - 严重问题 (导致 20 个套件失败)
|
||||
|
||||
#### 问题 1: Electron Mock 不完整
|
||||
|
||||
**文件**: `tests/setup.ts`
|
||||
|
||||
**当前 Mock**:
|
||||
|
||||
```typescript
|
||||
vi.mock('electron', () => ({
|
||||
app: {
|
||||
isPackaged: false,
|
||||
isReady: vi.fn().mockReturnValue(false),
|
||||
getPath: vi.fn().mockReturnValue(path.join(process.cwd(), 'logs')),
|
||||
on: vi.fn()
|
||||
}
|
||||
}))
|
||||
```
|
||||
|
||||
**缺失方法**:
|
||||
|
||||
- `getVersion()` - 导致 20 个套件失败
|
||||
- `getName()`
|
||||
- `getAppPath()`
|
||||
- `getVersion()` 在以下位置被调用:
|
||||
- `src/main/services/logger/index.ts:220`
|
||||
- `src/main/services/erp/cleaner.ts`
|
||||
- `src/main/services/erp/extractor.ts`
|
||||
- `src/main/services/erp/erp-auth.ts`
|
||||
- `src/main/services/database/mysql.ts`
|
||||
- `src/main/services/database/sql-server.ts`
|
||||
- `src/main/ipc/file-handler.ts`
|
||||
- `src/main/ipc/logger-handler.ts`
|
||||
- `src/main/services/excel/excel-parser.ts`
|
||||
- `src/main/services/config/config-manager.ts`
|
||||
- `src/main/services/update/*.ts`
|
||||
|
||||
**影响范围**: 所有导入 logger 或依赖 Electron app API 的模块
|
||||
|
||||
**修复方案**:
|
||||
|
||||
```typescript
|
||||
vi.mock('electron', () => ({
|
||||
app: {
|
||||
isPackaged: false,
|
||||
isReady: vi.fn().mockReturnValue(false),
|
||||
getPath: vi.fn().mockImplementation((name) => {
|
||||
switch (name) {
|
||||
case 'userData':
|
||||
return 'D:/test-user-data'
|
||||
case 'logs':
|
||||
return path.join(process.cwd(), 'test-logs')
|
||||
default:
|
||||
return '/tmp'
|
||||
}
|
||||
}),
|
||||
getVersion: vi.fn(() => '1.9.0-test'),
|
||||
getName: vi.fn(() => 'ERPAuto'),
|
||||
getAppPath: vi.fn(() => '/tmp/erpauto'),
|
||||
on: vi.fn(),
|
||||
isDefaultProtocolClient: vi.fn(() => true)
|
||||
},
|
||||
ipcMain: {
|
||||
handle: vi.fn(),
|
||||
on: vi.fn(),
|
||||
removeHandler: vi.fn(),
|
||||
removeListener: vi.fn()
|
||||
},
|
||||
dialog: {
|
||||
showErrorBox: vi.fn(),
|
||||
showMessageBox: vi.fn()
|
||||
},
|
||||
BrowserWindow: {
|
||||
getAllWindows: vi.fn(() => []),
|
||||
fromWebContents: vi.fn(() => null)
|
||||
}
|
||||
}))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 问题 2: Winston Logger Mock 不完整
|
||||
|
||||
**文件**: `tests/unit/logger.test.ts`
|
||||
|
||||
**问题代码**:
|
||||
|
||||
```typescript
|
||||
const formatFn = vi.fn((fn: any) => fn && fn()) as any
|
||||
formatFn.combine = vi.fn((...args) => args)
|
||||
formatFn.timestamp = vi.fn(() => ({ type: 'timestamp' }))
|
||||
formatFn.colorize = vi.fn(() => ({ type: 'colorize' }))
|
||||
formatFn.printf = vi.fn((fn: any) => fn)
|
||||
```
|
||||
|
||||
**问题**: `format().combine().timestamp().printf()` 链式调用失败
|
||||
|
||||
**修复方案**:
|
||||
|
||||
```typescript
|
||||
const createFormatFn = () => {
|
||||
const formatFn = vi.fn((fn) => fn) as any
|
||||
formatFn.combine = vi.fn((...args) => createFormatFn())
|
||||
formatFn.timestamp = vi.fn(() => createFormatFn())
|
||||
formatFn.colorize = vi.fn(() => createFormatFn())
|
||||
formatFn.printf = vi.fn((fn) => fn)
|
||||
formatFn.json = vi.fn(() => createFormatFn())
|
||||
formatFn.errors = vi.fn(() => createFormatFn())
|
||||
return formatFn
|
||||
}
|
||||
|
||||
const format = createFormatFn()
|
||||
|
||||
vi.mock('winston', () => ({
|
||||
default: {
|
||||
format,
|
||||
createLogger: vi.fn(() => createLoggerInstance),
|
||||
transports: {
|
||||
Console: vi.fn(),
|
||||
DailyRotateFile: vi.fn()
|
||||
}
|
||||
}
|
||||
}))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### P1 - 高优先级问题
|
||||
|
||||
#### 问题 3: 环境变量测试失败
|
||||
|
||||
**文件**: `tests/debug/env.test.ts`
|
||||
|
||||
**失败原因**: `.env` 文件缺少 ERP 凭据配置
|
||||
|
||||
**当前状态**:
|
||||
|
||||
```
|
||||
process.cwd(): D:\FileLib\Projects\CodeMigration\ERPAuto
|
||||
ERP_URL: (NOT SET)
|
||||
ERP_USERNAME: (NOT SET)
|
||||
ERP_PASSWORD: (NOT SET)
|
||||
Has Credentials: false
|
||||
```
|
||||
|
||||
**修复方案**: 创建 `tests/.env.test` 文件
|
||||
|
||||
```env
|
||||
# Test Environment Configuration
|
||||
ERP_URL=https://erp-test.example.com
|
||||
ERP_USERNAME=test_user
|
||||
ERP_PASSWORD=test_password
|
||||
|
||||
# Database Test Configuration
|
||||
MYSQL_HOST=localhost
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_DATABASE=erpauto_test
|
||||
MYSQL_USERNAME=test
|
||||
MYSQL_PASSWORD=test
|
||||
|
||||
SQLSERVER_SERVER=localhost
|
||||
SQLSERVER_PORT=1433
|
||||
SQLSERVER_DATABASE=erpauto_test
|
||||
SQLSERVER_USERNAME=test
|
||||
SQLSERVER_PASSWORD=test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 问题 4: 空测试文件 (17 个)
|
||||
|
||||
**单元测试 (8 个)**:
|
||||
|
||||
- `tests/unit/cleaner.test.ts`
|
||||
- `tests/unit/extractor.test.ts`
|
||||
- `tests/unit/excel-parser.test.ts`
|
||||
- `tests/unit/mysql.test.ts`
|
||||
- `tests/unit/sql-server.test.ts`
|
||||
- `tests/unit/data-importer.test.ts`
|
||||
- `tests/unit/ipc-index.test.ts`
|
||||
- `tests/unit/file-ipc-paths.test.ts`
|
||||
|
||||
**集成测试 (6 个)**:
|
||||
|
||||
- `tests/integration/cleaner.test.ts`
|
||||
- `tests/integration/extractor.test.ts`
|
||||
- `tests/integration/erp-auth.test.ts`
|
||||
- `tests/integration/mysql.test.ts`
|
||||
- `tests/integration/sql-server.test.ts`
|
||||
- `tests/integration/ipc-logging.test.ts`
|
||||
|
||||
**其他 (3 个)**:
|
||||
|
||||
- `tests/unit/update-catalog-service.test.ts`
|
||||
- `tests/unit/update-installer.test.ts`
|
||||
- `tests/unit/production-input-service.test.ts`
|
||||
|
||||
**影响**: 测试覆盖率为 0%,这些模块无自动化测试保护
|
||||
|
||||
---
|
||||
|
||||
#### 问题 5: E2E 测试覆盖不足
|
||||
|
||||
**当前状态**: 仅 3 个 E2E 测试文件
|
||||
|
||||
- `auth-flow.test.ts` - 登录流程
|
||||
- `dialog-focus.test.ts` - 对话框焦点
|
||||
- `extractor-workflow.test.ts` - 提取工作流
|
||||
|
||||
**缺失覆盖**:
|
||||
|
||||
- 物料清理工作流
|
||||
- 配置管理
|
||||
- 用户管理
|
||||
- 错误处理流程
|
||||
- 更新功能
|
||||
|
||||
---
|
||||
|
||||
### P2 - 中等优先级问题
|
||||
|
||||
#### 问题 6: 错误处理函数行为变更
|
||||
|
||||
**文件**: `tests/unit/errors.test.ts`
|
||||
|
||||
**失败测试**:
|
||||
|
||||
```typescript
|
||||
it('getErrorMessage should handle unknown types', () => {
|
||||
expect(getErrorMessage('string error')).toBe('string error')
|
||||
// 失败:实际返回 'An unknown error occurred'
|
||||
})
|
||||
```
|
||||
|
||||
**根因**: `getErrorMessage` 实现逻辑变更,测试未同步更新
|
||||
|
||||
---
|
||||
|
||||
#### 问题 7: 缺少测试数据工厂
|
||||
|
||||
**当前状态**: 测试数据分散在各测试文件中
|
||||
|
||||
- 无中央测试数据工厂
|
||||
- 重复的测试数据创建逻辑
|
||||
- 测试数据一致性难以保证
|
||||
|
||||
**建议**: 创建 `tests/fixtures/factories.ts`
|
||||
|
||||
```typescript
|
||||
export function createMockUser(overrides = {}) {
|
||||
return {
|
||||
id: 'user-' + Math.random().toString(36).substr(2, 9),
|
||||
username: 'test_user',
|
||||
role: 'User',
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
export function createMockOrder(overrides = {}) {
|
||||
return {
|
||||
orderNumber: 'ORD-' + Date.now(),
|
||||
materialCodes: ['MAT-001', 'MAT-002'],
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 优秀测试实践
|
||||
|
||||
### 1. Request Context 测试 (request-context.test.ts)
|
||||
|
||||
**特点**:
|
||||
|
||||
- 432 行完整的 AsyncLocalStorage 测试
|
||||
- 覆盖所有边界情况
|
||||
- 良好的测试分组和命名
|
||||
- 包含并发请求隔离测试
|
||||
|
||||
**值得学习**:
|
||||
|
||||
```typescript
|
||||
describe('Concurrent Request Isolation', () => {
|
||||
it('should maintain separate contexts for concurrent requests', async () => {
|
||||
const request1Ids: (string | undefined)[] = []
|
||||
const request2Ids: (string | undefined)[] = []
|
||||
|
||||
const promise1 = run(
|
||||
async () => {
|
||||
request1Ids.push(getRequestId())
|
||||
await new Promise((resolve) => setTimeout(resolve, 10))
|
||||
request1Ids.push(getRequestId())
|
||||
},
|
||||
{ userId: 'user-1', operation: 'extract' }
|
||||
)
|
||||
|
||||
const promise2 = run(
|
||||
async () => {
|
||||
request2Ids.push(getRequestId())
|
||||
await new Promise((resolve) => setTimeout(resolve, 5))
|
||||
request2Ids.push(getRequestId())
|
||||
},
|
||||
{ userId: 'user-2', operation: 'clean' }
|
||||
)
|
||||
|
||||
await Promise.all([promise1, promise2])
|
||||
|
||||
// 验证隔离性
|
||||
expect(request1Ids[0]).not.toBe(request2Ids[0])
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Error Utils 测试 (error-utils.test.ts)
|
||||
|
||||
**特点**:
|
||||
|
||||
- 561 行完整的错误处理测试
|
||||
- 覆盖序列化、清理、格式化
|
||||
- 包含 requestId 自动注入测试
|
||||
- 良好的 backward compatibility 测试
|
||||
|
||||
**值得学习**:
|
||||
|
||||
```typescript
|
||||
describe('sanitizeError', () => {
|
||||
it('should sanitize custom properties by key name pattern', () => {
|
||||
const error: SerializedError = {
|
||||
name: 'ConfigError',
|
||||
message: 'Config failed',
|
||||
password: 'secret123',
|
||||
secretKey: 'my-secret'
|
||||
}
|
||||
|
||||
const sanitized = sanitizeError(error)
|
||||
|
||||
expect(sanitized.password).toBe('[REDACTED]')
|
||||
expect(sanitized.secretKey).toBe('[REDACTED]')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. 集成测试可用性检查模式
|
||||
|
||||
**特点**: 优雅处理外部依赖缺失
|
||||
|
||||
```typescript
|
||||
const hasCredentials = !!(config.url && config.username && config.password)
|
||||
|
||||
beforeAll(() => {
|
||||
if (!hasCredentials) {
|
||||
console.warn('Skipping ERP auth tests: credentials not configured')
|
||||
return
|
||||
}
|
||||
authService = new ErpAuthService(config)
|
||||
})
|
||||
|
||||
it('should login successfully', async () => {
|
||||
if (!hasCredentials) {
|
||||
console.warn('Skipping test: ERP credentials not configured')
|
||||
return
|
||||
}
|
||||
const session = await authService.login()
|
||||
expect(session.isLoggedIn).toBe(true)
|
||||
}, 30000)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 测试质量评估
|
||||
|
||||
### 测试覆盖率分析
|
||||
|
||||
| 模块类型 | 文件数 | 有测试 | 测试质量 | 覆盖率估计 |
|
||||
| --------------- | ------ | ------ | -------- | ---------- |
|
||||
| **服务层** | ~15 | 8 | 中 | ~40% |
|
||||
| **数据库** | 4 | 0 | 无 | 0% |
|
||||
| **IPC** | ~10 | 2 | 中 | ~20% |
|
||||
| **工具类** | ~8 | 6 | 高 | ~80% |
|
||||
| **React Hooks** | ~5 | 2 | 中 | ~40% |
|
||||
| **E2E 场景** | N/A | 3 | 中 | ~15% |
|
||||
|
||||
### 测试健康状况
|
||||
|
||||
| 指标 | 状态 | 目标 |
|
||||
| ----------- | ------ | ---- |
|
||||
| 套件通过率 | 55% | 100% |
|
||||
| 用例通过率 | 67% | 95%+ |
|
||||
| 空测试文件 | 17 个 | 0 个 |
|
||||
| Mock 完整性 | 中 | 高 |
|
||||
| E2E 覆盖 | 低 | 中 |
|
||||
| 覆盖率阈值 | 无配置 | 70%+ |
|
||||
|
||||
---
|
||||
|
||||
## 🎯 改进计划
|
||||
|
||||
改进计划详情请参阅:[docs/test-improvement-plan.md](./test-improvement-plan.md)
|
||||
|
||||
### 阶段 1: 立即修复 (第 1-2 周) - P0
|
||||
|
||||
| 任务 | 描述 | 预计工时 | 成功标准 |
|
||||
| ---- | ------------------ | -------- | ------------------- |
|
||||
| 1.1 | 完成 Electron Mock | 2h | 20 个套件全部通过 |
|
||||
| 1.2 | 修复 Winston Mock | 2h | Logger 测试全部通过 |
|
||||
| 1.3 | 创建测试环境配置 | 1h | 环境测试通过 |
|
||||
|
||||
**预期结果**: 消除全部 48 个失败,通过率提升至 100%
|
||||
|
||||
---
|
||||
|
||||
### 阶段 2: 短期改进 (第 3-6 周) - P1
|
||||
|
||||
| 任务 | 描述 | 预计工时 | 成功标准 |
|
||||
| ---- | ----------------------- | -------- | ----------------- |
|
||||
| 2.1 | 填充单元测试 (8 个文件) | 16h | 新增 50+ 测试用例 |
|
||||
| 2.2 | 完成集成测试 (6 个文件) | 12h | 新增 30+ 测试用例 |
|
||||
| 2.3 | 修复 28 个现有失败用例 | 8h | 用例通过率 100% |
|
||||
|
||||
**预期结果**: 测试用例总数达 380+,关键模块覆盖率达 80%
|
||||
|
||||
---
|
||||
|
||||
### 阶段 3: 中期目标 (第 2-3 月) - P2
|
||||
|
||||
| 任务 | 描述 | 预计工时 | 成功标准 |
|
||||
| ---- | ------------------------ | -------- | ------------------ |
|
||||
| 3.1 | E2E 覆盖扩展至 12 个文件 | 20h | 50+ E2E 测试用例 |
|
||||
| 3.2 | 创建测试数据工厂 | 8h | 统一测试数据创建 |
|
||||
| 3.3 | 测试覆盖率阈值配置 | 4h | 70% 全局,80% 关键 |
|
||||
|
||||
**预期结果**: E2E 覆盖关键用户旅程,覆盖率达标
|
||||
|
||||
---
|
||||
|
||||
### 阶段 4: 长期战略 (第 4-6 月) - P3
|
||||
|
||||
| 任务 | 描述 | 预计工时 | 成功标准 |
|
||||
| ---- | ---------------------- | -------- | --------------- |
|
||||
| 4.1 | GitHub Actions CI 集成 | 8h | PR 自动运行测试 |
|
||||
| 4.2 | 测试健康监控仪表板 | 12h | 实时覆盖率追踪 |
|
||||
| 4.3 | 变异测试试点 | 16h | 测试质量提升 |
|
||||
|
||||
**预期结果**: 完整的 CI/CD 测试流水线,自动化测试文化
|
||||
|
||||
---
|
||||
|
||||
## 📋 行动项清单
|
||||
|
||||
### 立即执行 (本周)
|
||||
|
||||
- [ ] 更新 `tests/setup.ts` 添加完整 Electron Mock
|
||||
- [ ] 修复 `tests/unit/logger.test.ts` Winston Mock
|
||||
- [ ] 创建 `tests/.env.test` 测试环境配置
|
||||
- [ ] 运行 `npm run test:run` 验证修复效果
|
||||
|
||||
### 短期执行 (本月)
|
||||
|
||||
- [ ] 为 8 个空单元测试文件添加测试
|
||||
- [ ] 为 6 个空集成测试文件添加测试
|
||||
- [ ] 创建 `tests/fixtures/factories.ts` 测试数据工厂
|
||||
- [ ] 修复所有失败的测试用例
|
||||
|
||||
### 中期执行 (本季度)
|
||||
|
||||
- [ ] 扩展 E2E 测试至 12 个文件
|
||||
- [ ] 配置 vitest 覆盖率阈值
|
||||
- [ ] 建立测试审查流程
|
||||
- [ ] 编写测试最佳实践文档
|
||||
|
||||
---
|
||||
|
||||
## 📚 附录
|
||||
|
||||
### A. 测试运行命令
|
||||
|
||||
```bash
|
||||
# 全量测试
|
||||
npm run test:run
|
||||
|
||||
# 带覆盖率测试
|
||||
npm run test:coverage
|
||||
|
||||
# 单次运行特定文件
|
||||
npx vitest run tests/unit/request-context.test.ts
|
||||
|
||||
# 监听模式
|
||||
npm run test
|
||||
|
||||
# E2E 测试
|
||||
npm run test:e2e
|
||||
|
||||
# E2E 报告
|
||||
npm run test:e2e:report
|
||||
```
|
||||
|
||||
### B. 关键文件参考
|
||||
|
||||
| 文件 | 用途 |
|
||||
| ----------------------------------- | ---------------- |
|
||||
| `vitest.config.ts` | Vitest 配置 |
|
||||
| `playwright.config.ts` | Playwright 配置 |
|
||||
| `tests/setup.ts` | 全局 Setup/Mocks |
|
||||
| `tests/fixtures/create-fixtures.ts` | 测试数据生成 |
|
||||
|
||||
### C. 测试模式参考
|
||||
|
||||
**单元测试模板**:
|
||||
|
||||
```typescript
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
|
||||
|
||||
describe('ServiceName', () => {
|
||||
let service: ServiceClass
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
service = new ServiceClass(config)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
describe('methodName', () => {
|
||||
it('should do something', async () => {
|
||||
const result = await service.methodName()
|
||||
expect(result).toBeDefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
**集成测试模板**:
|
||||
|
||||
```typescript
|
||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
|
||||
|
||||
const hasCredentials = !!process.env.TEST_DB_HOST
|
||||
|
||||
describe('DatabaseService Integration', () => {
|
||||
let service: DatabaseService
|
||||
|
||||
beforeAll(async () => {
|
||||
if (!hasCredentials) {
|
||||
console.warn('Skipping: DB credentials not configured')
|
||||
return
|
||||
}
|
||||
service = new DatabaseService(testConfig)
|
||||
await service.connect()
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
if (service) await service.disconnect()
|
||||
})
|
||||
|
||||
it.skipIf(!hasCredentials)('should connect to database', async () => {
|
||||
expect(service.isConnected()).toBe(true)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**审查结论**: 项目测试基础良好,但存在关键 Mock 不完整和覆盖率缺口问题。建议优先修复 P0/P1 问题,然后系统性扩展测试覆盖。
|
||||
Reference in New Issue
Block a user