test-master
SKILL.md
测试大师
全面的测试专家,以三种思维模式确保软件质量:[功能] 正确性、[性能] 效率、[安全] 防护。
核心工作流
- 定义范围 — 确定需要测试的内容和测试类型
- 制定策略 — 从功能/性能/安全三个角度规划测试方案
- 编写测试 — 实现测试用例和断言
- 执行验证 — 运行测试并收集结果
- 报告反馈 — 记录发现并提出可执行的建议
使用内置工具
| 测试阶段 | 工具 | 用法 |
|---|---|---|
| 读取被测代码 | read_file |
理解要测试的功能逻辑 |
| 创建测试文件 | create_file_or_folder + rewrite_file |
创建测试文件并写入测试代码 |
| 运行测试 | run_command |
npx jest, npx vitest, pytest, go test |
| 查看覆盖率 | run_command |
npx jest --coverage, pytest --cov |
| 浏览器E2E | browser_action |
使用内置浏览器进行端到端测试(参见 webapp-testing 技能) |
| 编辑测试 | edit_file |
修改和完善测试用例 |
测试金字塔
/ E2E \ ← 少量,验证完整用户流程
/ 集成测试 \ ← 适量,验证模块间协作
/ 单元测试 \ ← 大量,验证单个函数/类
| 层级 | 数量占比 | 速度 | 隔离度 | 测试什么 |
|---|---|---|---|---|
| 单元测试 | ~70% | 毫秒级 | 完全隔离 | 单个函数/类的逻辑 |
| 集成测试 | ~20% | 秒级 | 部分隔离 | 模块间交互、API、数据库 |
| E2E 测试 | ~10% | 分钟级 | 无隔离 | 完整用户流程 |
单元测试模式
Jest/Vitest (TypeScript)
describe('UserService', () => {
let service: UserService;
let mockRepo: jest.Mocked<UserRepository>;
beforeEach(() => {
mockRepo = { findById: jest.fn(), save: jest.fn() } as any;
service = new UserService(mockRepo);
});
afterEach(() => jest.clearAllMocks());
describe('getUser', () => {
it('returns user when found', async () => {
const user = { id: '1', name: 'Test' };
mockRepo.findById.mockResolvedValue(user);
const result = await service.getUser('1');
expect(result).toEqual(user);
expect(mockRepo.findById).toHaveBeenCalledWith('1');
});
it('throws NotFoundError when user not found', async () => {
mockRepo.findById.mockResolvedValue(null);
await expect(service.getUser('1')).rejects.toThrow(NotFoundError);
});
});
});
pytest (Python)
import pytest
from unittest.mock import Mock, AsyncMock
class TestUserService:
@pytest.fixture
def mock_repo(self):
return Mock()
@pytest.fixture
def service(self, mock_repo):
return UserService(mock_repo)
async def test_get_user_returns_user(self, service, mock_repo):
mock_repo.find_by_id = AsyncMock(return_value={"id": "1", "name": "Test"})
result = await service.get_user("1")
assert result == {"id": "1", "name": "Test"}
async def test_get_user_raises_not_found(self, service, mock_repo):
mock_repo.find_by_id = AsyncMock(return_value=None)
with pytest.raises(NotFoundError):
await service.get_user("1")
测试组织结构
describe('Feature', () => {
describe('happy path', () => {
it('does expected behavior', () => {});
});
describe('edge cases', () => {
it('handles empty input', () => {});
it('handles max values', () => {});
it('handles null/undefined', () => {});
});
describe('error cases', () => {
it('throws on invalid input', () => {});
it('handles network failure', () => {});
});
});
Mock 模式速查
// Mock 函数
const mockFn = jest.fn();
mockFn.mockReturnValue('value');
mockFn.mockResolvedValue('async value');
mockFn.mockRejectedValue(new Error('error'));
// Mock 模块
jest.mock('./database', () => ({
query: jest.fn(),
}));
// Spy 已有方法
jest.spyOn(console, 'log').mockImplementation(() => {});
// Mock 网络请求
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({ data: 'test' }),
});
集成测试模式
// API 集成测试 (Supertest)
import request from 'supertest';
describe('POST /api/users', () => {
it('creates user with valid data', async () => {
const response = await request(app)
.post('/api/users')
.send({ name: 'Test', email: 'test@example.com' })
.expect(201);
expect(response.body).toMatchObject({
name: 'Test',
email: 'test@example.com',
});
});
it('returns 400 for invalid email', async () => {
await request(app)
.post('/api/users')
.send({ name: 'Test', email: 'invalid' })
.expect(400);
});
});
性能测试要点
| 指标 | 目标 | 测量方式 |
|---|---|---|
| 响应时间 | P95 < 200ms | k6, Artillery |
| 吞吐量 | > 1000 RPS | 负载测试工具 |
| 内存使用 | 无持续增长 | process.memoryUsage() |
| 启动时间 | < 3 秒 | 计时测量 |
// 简单性能基准
const start = performance.now();
await functionToTest();
const duration = performance.now() - start;
expect(duration).toBeLessThan(100); // 低于 100ms
安全测试检查清单
- SQL 注入:使用参数化查询
- XSS:输出正确编码
- CSRF:令牌验证
- 认证绕过:所有受保护路由检查 auth
- 授权提权:用户只能访问自己的资源
- 密钥泄露:无硬编码密钥/密码
- 依赖漏洞:
npm audit/pip audit
TDD 铁律
- 红 — 先写一个失败的测试
- 绿 — 写最少的代码让测试通过
- 重构 — 在不改变行为的前提下改进代码
- 每个循环不超过 5 分钟
测试报告模板
## 测试报告: [功能/模块名]
### 测试范围
- 单元测试: X 个用例
- 集成测试: X 个用例
- E2E 测试: X 个流程
### 覆盖率
- 语句覆盖: XX%
- 分支覆盖: XX%
- 函数覆盖: XX%
### 发现的问题
| 严重性 | 描述 | 位置 | 修复建议 |
|--------|------|------|---------|
| 严重 | ... | ... | ... |
### 建议
- [待补充的测试用例]
- [需要提高覆盖率的模块]
测试原则
必须做
- 测试正常路径和错误路径
- Mock 外部依赖(数据库、API、文件系统)
- 使用有意义的测试描述(读起来像规格说明)
- 断言具体结果(不只是 "不抛异常")
- 测试边界情况(空输入、最大值、特殊字符)
- 在 CI/CD 中运行测试
绝不做
- 跳过错误场景测试
- 使用生产数据
- 创建顺序依赖的测试
- 忽略 flaky 测试
- 测试实现细节(而非行为)
- 留下调试代码在测试中
知识参考
Jest、Vitest、pytest、React Testing Library、Supertest、Playwright、Cypress、k6、Artillery、OWASP 测试、代码覆盖率、Mocking、Fixtures、TDD、BDD、Page Object Model、Screenplay Pattern
Weekly Installs
1
Repository
senweaver/senweaver-ideGitHub Stars
15
First Seen
13 days ago
Security Audits
Installed on
amp1
cline1
opencode1
cursor1
kimi-cli1
codex1