Files
novalon-website/docs/plans/2026-03-10-gradual-coverage-improvement.md
T

580 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 渐进式测试覆盖率提升计划
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 建立可持续的测试覆盖率提升体系,从当前29.5%逐步提升到更高水平,同时保证开发效率和代码质量。
**Architecture:** 采用分层覆盖率策略,核心业务逻辑层高覆盖(70-80%),UI组件层中覆盖(60-70%),页面展示层适度覆盖(40-50%)。
**Tech Stack:** Jest, React Testing Library, Next.js, TypeScript, GitHub Actions
---
## 已完成任务
### Task 1: 调整Jest配置覆盖率阈值
**Files:**
- Modify: `jest.config.js:12-18`
**Step 1: 修改覆盖率阈值为合理水平**
```javascript
coverageThreshold: {
global: {
branches: 20,
functions: 25,
lines: 25,
statements: 25,
},
},
```
**Step 2: 运行测试验证配置**
Run: `npm run test:unit -- --coverage --coverageReporters=text-summary`
Expected: PASS with coverage above 25%
**Step 3: 提交配置修改**
```bash
git add jest.config.js
git commit -m "test: adjust coverage threshold to reasonable level (25%)"
```
---
## 第一阶段:稳定当前覆盖率(1-2周)
### Task 2: 补充核心业务逻辑测试
**Files:**
- Create: `src/lib/auth/session.test.ts`
- Create: `src/lib/auth/token.test.ts`
- Create: `src/lib/validation.test.ts`
**Step 1: 为session管理编写测试**
```typescript
describe('session management', () => {
it('should create session with user data', () => {
const session = createSession({ userId: '123', role: 'admin' });
expect(session).toBeDefined();
expect(session.userId).toBe('123');
});
it('should validate session expiration', () => {
const expiredSession = createSession({ userId: '123', expiresIn: -1 });
expect(isSessionValid(expiredSession)).toBe(false);
});
});
```
**Step 2: 运行测试验证失败**
Run: `npm run test:unit -- --testPathPattern="session.test.ts"`
Expected: FAIL with "createSession not defined"
**Step 3: 实现session管理功能**
```typescript
export function createSession(userData: SessionData): Session {
return {
...userData,
createdAt: Date.now(),
expiresAt: Date.now() + (24 * 60 * 60 * 1000), // 24小时
};
}
export function isSessionValid(session: Session): boolean {
return Date.now() < session.expiresAt;
}
```
**Step 4: 运行测试验证通过**
Run: `npm run test:unit -- --testPathPattern="session.test.ts"`
Expected: PASS
**Step 5: 提交**
```bash
git add src/lib/auth/session.test.ts src/lib/auth/session.ts
git commit -m "test: add session management tests"
```
---
### Task 3: 补充数据验证测试
**Files:**
- Create: `src/lib/validation.test.ts`
- Modify: `src/lib/validation.ts`
**Step 1: 编写数据验证测试**
```typescript
describe('validation', () => {
describe('email validation', () => {
it('should accept valid email', () => {
expect(validateEmail('test@example.com')).toBe(true);
});
it('should reject invalid email', () => {
expect(validateEmail('invalid')).toBe(false);
});
});
describe('phone validation', () => {
it('should accept valid phone', () => {
expect(validatePhone('13800138000')).toBe(true);
});
it('should reject invalid phone', () => {
expect(validatePhone('123')).toBe(false);
});
});
});
```
**Step 2: 运行测试验证失败**
Run: `npm run test:unit -- --testPathPattern="validation.test.ts"`
Expected: FAIL with validation functions not defined
**Step 3: 实现验证函数**
```typescript
export function validateEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
export function validatePhone(phone: string): boolean {
const phoneRegex = /^1[3-9]\d{9}$/;
return phoneRegex.test(phone);
}
```
**Step 4: 运行测试验证通过**
Run: `npm run test:unit -- --testPathPattern="validation.test.ts"`
Expected: PASS
**Step 5: 提交**
```bash
git add src/lib/validation.test.ts src/lib/validation.ts
git commit -m "test: add data validation tests"
```
---
### Task 4: 优化测试执行性能
**Files:**
- Modify: `jest.config.js`
- Create: `.github/workflows/test-optimized.yml`
**Step 1: 配置并行测试执行**
```javascript
// jest.config.js
module.exports = {
// ... existing config
maxWorkers: '50%',
};
```
**Step 2: 创建优化后的CI工作流**
```yaml
# .github/workflows/test-optimized.yml
name: Optimized Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
shard: [1, 2, 3, 4]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run tests (shard ${{ matrix.shard }})
run: npm run test:unit -- --shard=${{ matrix.shard }}/4
- name: Upload coverage
if: matrix.shard == 4
uses: codecov/codecov-action@v4
```
**Step 3: 提交配置**
```bash
git add jest.config.js .github/workflows/test-optimized.yml
git commit -m "ci: optimize test execution with parallelization"
```
---
## 第二阶段:提升覆盖率到35%(1-2个月)
### Task 5: 补充API路由测试
**Files:**
- Create: `src/app/api/contact/route.test.ts`
- Create: `src/app/api/auth/route.test.ts`
**Step 1: 编写API路由测试**
```typescript
describe('/api/contact', () => {
it('should handle POST request', async () => {
const response = await POST(new Request('http://localhost/api/contact', {
method: 'POST',
body: JSON.stringify({ name: 'Test', email: 'test@example.com' }),
}));
expect(response.status).toBe(200);
});
it('should validate required fields', async () => {
const response = await POST(new Request('http://localhost/api/contact', {
method: 'POST',
body: JSON.stringify({}),
}));
expect(response.status).toBe(400);
});
});
```
**Step 2: 运行测试验证失败**
Run: `npm run test:unit -- --testPathPattern="api/contact/route.test.ts"`
Expected: FAIL with API route not tested
**Step 3: 实现API路由验证逻辑**
```typescript
// 确保API路由有适当的验证和错误处理
export async function POST(request: Request) {
try {
const body = await request.json();
if (!body.name || !body.email) {
return Response.json({ error: 'Missing required fields' }, { status: 400 });
}
// 处理逻辑...
return Response.json({ success: true }, { status: 200 });
} catch (error) {
return Response.json({ error: 'Internal server error' }, { status: 500 });
}
}
```
**Step 4: 运行测试验证通过**
Run: `npm run test:unit -- --testPathPattern="api/contact/route.test.ts"`
Expected: PASS
**Step 5: 提交**
```bash
git add src/app/api/contact/route.test.ts src/app/api/contact/route.ts
git commit -m "test: add API route tests"
```
---
### Task 6: 补充数据库操作测试
**Files:**
- Create: `src/db/queries.test.ts`
- Create: `src/db/mutations.test.ts`
**Step 1: 编写数据库查询测试**
```typescript
describe('database queries', () => {
it('should query user by id', async () => {
const user = await getUserById('123');
expect(user).toBeDefined();
expect(user.id).toBe('123');
});
it('should return null for non-existent user', async () => {
const user = await getUserById('non-existent');
expect(user).toBeNull();
});
});
```
**Step 2: 运行测试验证失败**
Run: `npm run test:unit -- --testPathPattern="db/queries.test.ts"`
Expected: FAIL with database functions not tested
**Step 3: 实现数据库查询函数**
```typescript
export async function getUserById(id: string): Promise<User | null> {
const result = await db.select().from(users).where(eq(users.id, id)).limit(1);
return result[0] || null;
}
```
**Step 4: 运行测试验证通过**
Run: `npm run test:unit -- --testPathPattern="db/queries.test.ts"`
Expected: PASS
**Step 5: 提交**
```bash
git add src/db/queries.test.ts src/db/queries.ts
git commit -m "test: add database query tests"
```
---
### Task 7: 提升分支覆盖率
**Files:**
- Modify: `src/lib/auth/permissions.test.ts`
- Modify: `src/lib/upload.test.ts`
**Step 1: 添加边界条件测试**
```typescript
describe('permissions edge cases', () => {
it('should handle null role', () => {
expect(hasPermission(null, 'content', 'read')).toBe(false);
});
it('should handle undefined resource', () => {
expect(hasPermission('admin', undefined, 'read')).toBe(false);
});
it('should handle empty action string', () => {
expect(hasPermission('admin', 'content', '')).toBe(false);
});
});
```
**Step 2: 运行测试验证通过**
Run: `npm run test:unit -- --testPathPattern="permissions.test.ts"`
Expected: PASS with improved branch coverage
**Step 3: 提交**
```bash
git add src/lib/auth/permissions.test.ts
git commit -m "test: improve branch coverage with edge cases"
```
---
## 第三阶段:建立测试质量体系(2-3个月)
### Task 8: 创建测试指南文档
**Files:**
- Create: `docs/testing-guide.md`
**Step 1: 编写测试指南**
```markdown
# 测试指南
## 测试策略
本项目采用分层覆盖率策略:
- 核心业务逻辑层:70-80%覆盖率
- UI组件层:60-70%覆盖率
- 页面展示层:40-50%覆盖率
## 测试编写规范
### 单元测试
- 使用Jest和React Testing Library
- 遵循AAA模式(Arrange-Act-Assert
- 每个测试只验证一个行为
### 集成测试
- 测试组件间的交互
- 使用真实的数据流
- 避免过度mock
## 常见问题
**Q: 如何处理异步测试?**
A: 使用async/await和waitFor函数。
**Q: 如何测试错误处理?**
A: 使用toThrow和expect.assertions验证错误路径。
```
**Step 2: 提交文档**
```bash
git add docs/testing-guide.md
git commit -m "docs: add testing guide"
```
---
### Task 9: 建立覆盖率趋势监控
**Files:**
- Create: `scripts/coverage-trend.js`
- Create: `.github/workflows/coverage-report.yml`
**Step 1: 创建覆盖率趋势脚本**
```javascript
// scripts/coverage-trend.js
const fs = require('fs');
const coverage = JSON.parse(fs.readFileSync('coverage/coverage-final.json', 'utf8'));
const metrics = {
statements: coverage.total.statements.pct,
branches: coverage.total.branches.pct,
functions: coverage.total.functions.pct,
lines: coverage.total.lines.pct,
};
console.log(JSON.stringify(metrics, null, 2));
```
**Step 2: 创建覆盖率报告工作流**
```yaml
# .github/workflows/coverage-report.yml
name: Coverage Report
on:
push:
branches: [main]
jobs:
report:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate coverage
run: |
npm run test:unit -- --coverage
node scripts/coverage-trend.js > coverage-metrics.json
- name: Upload metrics
uses: actions/upload-artifact@v4
with:
name: coverage-metrics
path: coverage-metrics.json
```
**Step 3: 提交**
```bash
git add scripts/coverage-trend.js .github/workflows/coverage-report.yml
git commit -m "ci: add coverage trend monitoring"
```
---
### Task 10: 更新覆盖率目标
**Files:**
- Modify: `jest.config.js`
**Step 1: 提升覆盖率目标到35%**
```javascript
coverageThreshold: {
global: {
branches: 25,
functions: 35,
lines: 35,
statements: 35,
},
},
```
**Step 2: 运行测试验证**
Run: `npm run test:unit -- --coverage --coverageReporters=text-summary`
Expected: PASS with coverage above 35%
**Step 3: 提交**
```bash
git add jest.config.js
git commit -m "test: increase coverage threshold to 35%"
```
---
## 验证步骤
### 验证1: 确认所有测试通过
Run: `npm run test:unit`
Expected: All tests pass
### 验证2: 确认覆盖率达标
Run: `npm run test:unit -- --coverage --coverageReporters=text-summary`
Expected: Coverage above 35%
### 验证3: 确认CI构建通过
Check: GitHub Actions workflow status
Expected: All workflows pass
---
## 回滚计划
如果出现问题,可以回滚到之前的配置:
```bash
git log --oneline --all
git checkout <commit-hash>
```
---
## 相关资源
- [Jest文档](https://jestjs.io/docs/getting-started)
- [React Testing Library](https://testing-library.com/docs/react-testing-library/intro)
- [测试最佳实践](https://github.com/goldbergyoni/javascript-testing-best-practices)