🚀 快速安装
复制以下命令并运行,立即安装此 Skill:
npx @anthropic-ai/skills install supercent-io/skills-template/testing-strategies
💡 提示:需要 Node.js 和 NPM
测试策略
何时使用此技能
- 新项目:定义测试策略
- 质量问题:频繁出现错误
- 重构前:构建安全网
- CI/CD 设置:自动化测试
指示
步骤 1:理解测试金字塔
/\
/E2E\ ← 少量(慢,成本高)
/______\
/ \
/ 集成测试 \ ← 中等
/____________\
/ \
/ 单元测试 \ ← 大量(快,成本低)
/________________\
比例指南:
- 单元测试:70%
- 集成测试:20%
- 端到端测试:10%
步骤 2:单元测试策略
给定-当-那么模式:
describe('calculateDiscount', () => {
it('对于超过 100 美元的订单应应用 10% 折扣', () => {
// 给定:准备
const order = { total: 150, customerId: '123' };
// 当:执行操作
const discount = calculateDiscount(order);
// 那么:验证结果
expect(discount).toBe(15);
});
it('对于低于 100 美元的订单不应应用折扣', () => {
const order = { total: 50, customerId: '123' };
const discount = calculateDiscount(order);
expect(discount).toBe(0);
});
it('对于无效订单应抛出错误', () => {
const order = { total: -10, customerId: '123' };
expect(() => calculateDiscount(order)).toThrow('无效订单');
});
});
模拟策略:
// 模拟外部依赖
jest.mock('../services/emailService');
import { sendEmail } from '../services/emailService';
describe('UserService', () => {
it('注册时应发送欢迎邮件', async () => {
// 准备
const mockSendEmail = sendEmail as jest.MockedFunction<typeof sendEmail>;
mockSendEmail.mockResolvedValueOnce(true);
// 执行
await userService.register({ email: 'test@example.com', password: 'pass' });
// 断言
expect(mockSendEmail).toHaveBeenCalledWith({
to: 'test@example.com',
subject: '欢迎!',
body: expect.any(String)
});
});
});
步骤 3:集成测试
API 端点测试:
describe('POST /api/users', () => {
beforeEach(async () => {
await db.user.deleteMany(); // 清理数据库
});
it('应使用有效数据创建用户', async () => {
const response = await request(app)
.post('/api/users')
.send({
email: 'test@example.com',
username: 'testuser',
password: 'Password123!'
});
expect(response.status).toBe(201);
expect(response.body.user).toMatchObject({
email: 'test@example.com',
username: 'testuser'
});
// 验证它是否实际保存到数据库
const user = await db.user.findUnique({ where: { email: 'test@example.com' } });
expect(user).toBeTruthy();
});
it('应拒绝重复的邮箱', async () => {
// 创建第一个用户
await request(app)
.post('/api/users')
.send({ email: 'test@example.com', username: 'user1', password: 'Pass123!' });
// 尝试重复
const response = await request(app)
.post('/api/users')
.send({ email: 'test@example.com', username: 'user2', password: 'Pass123!' });
expect(response.status).toBe(409);
});
});
步骤 4:端到端测试(Playwright)
import { test, expect } from '@playwright/test';
test.describe('用户注册流程', () => {
test('应完成整个注册过程', async ({ page }) => {
// 1. 访问首页
await page.goto('http://localhost:3000');
// 2. 点击注册按钮
await page.click('text=注册');
// 3. 填写表单
await page.fill('input[name="email"]', 'test@example.com');
await page.fill('input[name="username"]', 'testuser');
await page.fill('input[name="password"]', 'Password123!');
// 4. 提交
await page.click('button[type="submit"]');
// 5. 确认成功消息
await expect(page.locator('text=欢迎')).toBeVisible();
// 6. 确认重定向到仪表板
await expect(page).toHaveURL('http://localhost:3000/dashboard');
// 7. 确认用户信息已显示
await expect(page.locator('text=testuser')).toBeVisible();
});
test('对于无效邮箱应显示错误', async ({ page }) => {
await page.goto('http://localhost:3000/signup');
await page.fill('input[name="email"]', 'invalid-email');
await page.fill('input[name="password"]', 'Password123!');
await page.click('button[type="submit"]');
await expect(page.locator('text=无效邮箱')).toBeVisible();
});
});
步骤 5:测试驱动开发
红-绿-重构循环:
// 1. 红:编写一个失败的测试
describe('isPalindrome', () => {
it('对于回文应返回 true', () => {
expect(isPalindrome('racecar')).toBe(true);
});
});
// 2. 绿:编写最少代码通过测试
function isPalindrome(str: string): boolean {
return str === str.split('').reverse().join('');
}
// 3. 重构:改进代码
function isPalindrome(str: string): boolean {
const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, '');
return cleaned === cleaned.split('').reverse().join('');
}
// 4. 添加更多测试用例
it('应忽略大小写和空格', () => {
expect(isPalindrome('A man a plan a canal Panama')).toBe(true);
});
it('对于非回文应返回 false', () => {
expect(isPalindrome('hello')).toBe(false);
});
输出格式
测试策略文档
## 测试策略
### 覆盖率目标
- 单元测试:80%
- 集成测试:60%
- 端到端测试:关键用户流程
### 测试执行
- 单元测试:每次提交(本地 + CI)
- 集成测试:每次拉取请求
- 端到端测试:部署前
### 工具
- 单元测试:Jest
- 集成测试:Supertest
- 端到端测试:Playwright
- 覆盖率:Istanbul/nyc
### CI/CD 集成
- GitHub Actions:在拉取请求上运行所有测试
- 如果覆盖率 < 80%,则构建失败
- 在预发布环境上运行端到端测试
约束条件
必需规则(必须遵守)
- 测试隔离:每个测试都是独立的
- 快速反馈:单元测试应该很快(<1 分钟)
- 确定性:相同输入 → 相同结果
禁止事项(不得违反)
- 测试依赖:不要让测试 A 依赖于测试 B
- 生产数据库:不要在测试中使用真实数据库
- 睡眠/超时:避免基于时间的测试
最佳实践
- AAA 模式:准备-执行-断言
- 测试命名:“应该…当…”
- 边缘情况:边界值、null、空值
- 快乐路径 + 悲伤路径:包括成功和失败场景
参考资料
元数据
版本
- 当前版本:1.0.0
- 最后更新:2025-01-01
- 兼容平台:Claude, ChatGPT, Gemini
相关技能
标签
#测试 #测试策略 #TDD #单元测试 #集成测试 #端到端测试 #代码质量
示例
示例 1:基本用法
示例 2:高级用法
📄 原始文档
完整文档(英文):
https://skills.sh/supercent-io/skills-template/testing-strategies
💡 提示:点击上方链接查看 skills.sh 原始英文文档,方便对照翻译。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

评论(0)