关于 test-coverage-improver
Test Coverage Improver 是用于发现测试缺口并补充测试、提升覆盖率的技能,提供覆盖率报告命令、测试示例以及分支和边界情况清单。
主要功能
- 01生成覆盖率报告
- 02优先处理测试缺口
- 03单元与异步测试示例
- 04模拟与组件测试示例
- 05分支和边界情况清单
适用场景
- 01查找未覆盖的关键代码路径
- 02为错误处理和边界情况添加测试
- 03提升 Jest 或 Vitest 项目的覆盖率
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ onewave-ai/ claude-skills --skill test-coverage-improver安装后在 Claude Code 中输入/test-coverage-improver确认已加载。
详细介绍
测试覆盖率改进器
说明
提高测试覆盖率时:
- 运行覆盖率报告,找出覆盖缺口
- 优先关注关键和复杂的代码路径
- 编写测试,覆盖未覆盖的代码
- 验证覆盖率已提高
生成覆盖率报告
# Jest
npx jest --coverage
# Vitest
npx vitest --coverage
# NYC (Istanbul) for any test runner
npx nyc npm test
# View HTML report
open coverage/lcov-report/index.html
覆盖率目标
| 类型 | 最低 | 良好 | 优秀 |
|---|---|---|---|
| 行 | 70% | 80% | 90%+ |
| 分支 | 60% | 75% | 85%+ |
| 函数 | 70% | 80% | 90%+ |
| 语句 | 70% | 80% | 90%+ |
测试模板
单元测试(Jest/Vitest)
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { calculateTotal, formatCurrency } from './utils';
describe('calculateTotal', () => {
it('should sum all item prices', () => {
const items = [
{ price: 10, quantity: 2 },
{ price: 5, quantity: 1 },
];
expect(calculateTotal(items)).toBe(25);
});
it('should return 0 for empty array', () => {
expect(calculateTotal([])).toBe(0);
});
it('should handle decimal prices', () => {
const items = [{ price: 10.99, quantity: 1 }];
expect(calculateTotal(items)).toBeCloseTo(10.99);
});
});
测试异步函数
describe('fetchUser', () => {
it('should return user data', async () => {
const user = await fetchUser(1);
expect(user).toEqual({
id: 1,
name: expect.any(String),
email: expect.stringContaining('@'),
});
});
it('should throw for non-existent user', async () => {
await expect(fetchUser(999)).rejects.toThrow('User not found');
});
});
模拟依赖项
import { vi } from 'vitest';
import { sendEmail } from './email';
import { createUser } from './user';
vi.mock('./email', () => ({
sendEmail: vi.fn().mockResolvedValue({ success: true }),
}));
describe('createUser', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('should send welcome email after creating user', async () => {
await createUser({ name: 'John', email: '[email protected]' });
expect(sendEmail).toHaveBeenCalledWith({
to: '[email protected]',
template: 'welcome',
});
});
});
React 组件测试
import { render, screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './Button';
describe('Button', () => {
it('should render children', () => {
render(<Button>Click me</Button>);
expect(screen.getByText('Click me')).toBeInTheDocument();
});
it('should call onClick when clicked', async () => {
const handleClick = vi.fn();
render(<Button onClick={handleClick}>Click</Button>);
await userEvent.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
it('should be disabled when loading', () => {
render(<Button isLoading>Submit</Button>);
expect(screen.getByRole('button')).toBeDisabled();
});
});
API 路由测试
import { createMocks } from 'node-mocks-http';
import handler from './api/users';
describe('GET /api/users', () => {
it('should return users list', async () => {
const { req, res } = createMocks({ method: 'GET' });
await handler(req, res);
expect(res._getStatusCode()).toBe(200);
expect(JSON.parse(res._getData())).toHaveProperty('users');
});
});
分支覆盖率检查清单
确保测试覆盖:
- If/else 分支
- 三元运算符
- Switch 分支(包括 default)
- Try/catch 块
- 提前返回
- 空值合并(
??) - 可选链结果(
?.) - 循环条件(0、1、多次迭代)
覆盖率配置
// vitest.config.ts
export default {
test: {
coverage: {
provider: 'v8',
reporter: ['text', 'html', 'lcov'],
exclude: [
'node_modules/',
'**/*.d.ts',
'**/*.test.ts',
'**/types/',
],
thresholds: {
lines: 80,
branches: 75,
functions: 80,
statements: 80,
},
},
},
};
测试优先级
- 关键路径:身份验证、支付、数据变更
- 复杂逻辑:算法、状态机、计算
- 错误处理程序:Catch 块、错误边界
- 边缘情况:空数组、null 值、边界条件
- 集成点:API 调用、数据库查询
评论
支持 Markdown