test: complete Wave 3 - Mock Library (6 tasks, 15+ Mock factories)
Wave 3: Mock Library Implementation ==================================== **Mock Factories (15+ total)**: - Logger/ConfigManager (createMockLogger, createMockConfigManager) - ErpAuthService (createMockErpAuthService with isLoggedIn/loginFails options) - TypeORM/Database (createMockDataSource, createMockRepository, createMockDatabaseService) - Electron/IPC (createMockElectron, createMockIpcRenderer) - Utility modules (createMockFs, createMockPath, createMockExcelJS, createMockAxios, createMockChildProcess, createMockCrypto) **Files Modified/Created**: - tests/mocks/types.ts: +243 lines (Mock type definitions) - tests/mocks/index.ts: +475 lines (Factory function implementations) - docs/MOCK_LIBRARY_USAGE.md: 197 lines (Usage guide with 12+ examples) - tests/unit/mocks/electron-ipc.test.ts: 12 tests (Electron/IPC Mock verification) **Quality**: - Zero any types - All Mocks ≤20-30 lines - Complete JSDoc documentation - All factory functions support overrides customization **Total Progress**: - Wave 1: 4/4 ✅ - Wave 2: 5/5 ✅ - Wave 3: 6/6 ✅ - Overall: 15/34 ✅
This commit is contained in:
197
docs/MOCK_LIBRARY_USAGE.md
Normal file
197
docs/MOCK_LIBRARY_USAGE.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# Mock Library 使用指南
|
||||
|
||||
ERPAuto 测试框架提供的 Mock 工厂函数,帮助你快速创建类型安全的测试替身。
|
||||
|
||||
## 快速开始
|
||||
|
||||
```typescript
|
||||
import { createMockLogger, createMockConfigManager } from '@/tests/mocks'
|
||||
|
||||
const mockLogger = createMockLogger()
|
||||
const mockConfig = createMockConfigManager({
|
||||
logging: { level: 'debug', auditRetention: 30, appRetention: 14 }
|
||||
})
|
||||
```
|
||||
|
||||
## Logger Mock
|
||||
|
||||
```typescript
|
||||
const mockLogger = createMockLogger()
|
||||
mockLogger.info('test')
|
||||
expect(mockLogger.info).toHaveBeenCalledWith('test')
|
||||
|
||||
// 预设行为
|
||||
const mockLogger = createMockLogger({
|
||||
error: vi.fn(() => console.log('logged'))
|
||||
})
|
||||
|
||||
// Child logger
|
||||
const child = mockLogger.child('OrderService')
|
||||
```
|
||||
|
||||
## ConfigManager Mock
|
||||
|
||||
```typescript
|
||||
const mockConfig = createMockConfigManager({
|
||||
logging: { level: 'debug' },
|
||||
erp: { url: 'https://test.local' }
|
||||
})
|
||||
|
||||
expect(mockConfig.getConfig().logging.level).toBe('debug')
|
||||
mockConfig.updateConfig.mockResolvedValue({ success: true })
|
||||
```
|
||||
|
||||
## ERP Auth Mock
|
||||
|
||||
```typescript
|
||||
const mockAuth = createMockErpAuthService({ isLoggedIn: true })
|
||||
expect(mockAuth.isActive()).toBe(true)
|
||||
|
||||
mockAuth.login.mockRejectedValue(new Error('Auth failed'))
|
||||
await expect(mockAuth.login()).rejects.toThrow()
|
||||
```
|
||||
|
||||
## Playwright Mock
|
||||
|
||||
```typescript
|
||||
const mockPage = createMockPage()
|
||||
mockPage.goto.mockResolvedValue(undefined)
|
||||
|
||||
const mockLocator = createMockLocator()
|
||||
mockLocator.fill.mockResolvedValue(undefined)
|
||||
mockLocator.click.mockResolvedValue(undefined)
|
||||
```
|
||||
|
||||
## 常见模式
|
||||
|
||||
### 1. Stubbing - 预设返回值
|
||||
|
||||
```typescript
|
||||
mockConfig.getConfig.mockReturnValue({ logging: { level: 'debug' } })
|
||||
mockConfig.updateConfig.mockResolvedValue({ success: true })
|
||||
```
|
||||
|
||||
### 2. Spying - 跟踪调用
|
||||
|
||||
```typescript
|
||||
service.doWork(mockLogger)
|
||||
expect(mockLogger.info).toHaveBeenCalledWith('Work started')
|
||||
```
|
||||
|
||||
### 3. Behavior Preset - 预设行为
|
||||
|
||||
```typescript
|
||||
mockAuth.login.mockRejectedValue(new Error('Auth failed'))
|
||||
await expect(mockAuth.login()).rejects.toThrow()
|
||||
```
|
||||
|
||||
## 反模式
|
||||
|
||||
### ❌ 复杂条件逻辑
|
||||
|
||||
```typescript
|
||||
// 错误
|
||||
mockConfig.getConfig.mockImplementation(() => {
|
||||
if (condition) return configA
|
||||
else return configB
|
||||
})
|
||||
|
||||
// 正确
|
||||
mockConfig.getConfig.mockReturnValue(fixedConfig)
|
||||
```
|
||||
|
||||
### ❌ 真实网络调用
|
||||
|
||||
```typescript
|
||||
// 错误
|
||||
mockPage.goto.mockImplementation(async (url) => {
|
||||
await fetch(url)
|
||||
})
|
||||
|
||||
// 正确
|
||||
mockPage.goto.mockResolvedValue(undefined)
|
||||
```
|
||||
|
||||
### ❌ 过度 Mock
|
||||
|
||||
```typescript
|
||||
// 错误:Mock 每个方法
|
||||
createMockLogger({
|
||||
info: vi.fn(),
|
||||
error: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
debug: vi.fn(),
|
||||
verbose: vi.fn(),
|
||||
child: vi.fn()
|
||||
})
|
||||
|
||||
// 正确:只覆盖需要的
|
||||
createMockLogger()
|
||||
createMockLogger({ error: vi.fn() })
|
||||
```
|
||||
|
||||
## 迁移指南
|
||||
|
||||
### vi.mock() → createMockXxx()
|
||||
|
||||
**旧方式**:
|
||||
|
||||
```typescript
|
||||
vi.mock('./logger', () => ({
|
||||
createLogger: vi.fn(() => ({ info: vi.fn() }))
|
||||
}))
|
||||
```
|
||||
|
||||
**新方式**:
|
||||
|
||||
```typescript
|
||||
import { createMockLogger } from '@/tests/mocks'
|
||||
const logger = createMockLogger()
|
||||
```
|
||||
|
||||
**优势**: 类型安全、预设默认值、统一维护
|
||||
|
||||
### 手写 Mock → 工厂函数
|
||||
|
||||
**旧方式**:
|
||||
|
||||
```typescript
|
||||
const mock = { getConfig: vi.fn(), updateConfig: vi.fn() }
|
||||
```
|
||||
|
||||
**新方式**:
|
||||
|
||||
```typescript
|
||||
const mock = createMockConfigManager()
|
||||
```
|
||||
|
||||
**优势**: 不遗漏方法、配置自动合并
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. 优先使用工厂函数
|
||||
2. 只 Mock 依赖,不 Mock 被测试类本身
|
||||
3. 保持 Mock 简单
|
||||
4. 用命名和注释说明 Mock 目的
|
||||
|
||||
## 完整示例
|
||||
|
||||
```typescript
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { createMockLogger, createMockConfigManager } from '@/tests/mocks'
|
||||
|
||||
describe('OrderService', () => {
|
||||
it('should process order', () => {
|
||||
const logger = createMockLogger()
|
||||
const config = createMockConfigManager({
|
||||
extraction: { batchSize: 100 }
|
||||
})
|
||||
|
||||
const service = new OrderService(logger, config)
|
||||
service.processOrder('ORD-001')
|
||||
|
||||
expect(logger.info).toHaveBeenCalledWith('Processing: ORD-001')
|
||||
expect(config.getConfig).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
```
|
||||
Reference in New Issue
Block a user