用途
tdd-workflow 是一个测试驱动开发(TDD)工作流技能,用于在开发过程中强制遵循测试先行的原则,并确保单元测试、集成测试和端到端(E2E)测试的全面覆盖。它适用于以下场景:编写新功能或功能模块、修复缺陷或问题、重构现有代码、添加 API 端点、创建新组件、实现业务逻辑。
主要能力
该技能围绕以下核心原则展开:
- 测试先于代码:始终先编写测试,再实现代码使测试通过,没有例外。
- 覆盖率要求:最低 80% 覆盖率(单元 + 集成 + E2E),覆盖所有边界情况、错误场景、边界条件,以及正常路径和异常路径。
- 测试金字塔:单元测试占 50-70%,集成测试占 20-30%,E2E 测试占 10-20%。
使用方式
TDD 工作流采用红-绿-重构(Red-Green-Refactor)循环:
步骤 1:RED — 编写失败测试 从用户故事出发,例如“作为用户,我希望按类别搜索产品,以便快速找到相关商品”,然后编写测试。示例代码:
describe('ProductSearch', () => {
it('returns products filtered by category', async () => {
const products = await searchProducts({ category: 'electronics' });
expect(products).toHaveLength(5);
expect(products.every(p => p.category === 'electronics')).toBe(true);
});
});
步骤 2:运行测试(应当失败)
npm test
# ✗ ProductSearch > returns products filtered by category
# TypeError: searchProducts is not a function
这是正常的,RED 阶段确认测试有效。
步骤 3:GREEN — 实现最小代码 编写刚好能让测试通过的代码:
export async function searchProducts(filters: SearchFilters) {
const { category } = filters;
return db.products.findMany({
where: { category }
});
}
步骤 4:运行测试(应当通过)
npm test
# ✓ ProductSearch > returns products filtered by category (42ms)
步骤 5:REFACTOR — 改进代码 在保持测试通过的前提下重构:
export async function searchProducts(filters: SearchFilters) {
const query = buildSearchQuery(filters);
const results = await executeSearch(query);
return transformResults(results);
}
再次运行测试确保仍然通过。
测试类型
单元测试:隔离测试单个函数。示例:
describe('calculateDiscount', () => {
it('applies 10% discount for basic tier', () => {
const price = calculateDiscount(100, 'basic');
expect(price).toBe(90);
});
it('applies 20% discount for premium tier', () => {
const price = calculateDiscount(100, 'premium');
expect(price).toBe(80);
});
it('throws error for invalid tier', () => {
expect(() => calculateDiscount(100, 'invalid')).toThrow();
});
});
集成测试:测试多个组件协同工作。示例:
describe('User Registration API', () => {
it('creates user and sends welcome email', async () => {
const response = await request(app)
.post('/api/register')
.send({ email: 'test@example.com', password: 'secret' }); // allow-secret
expect(response.status).toBe(201);
expect(response.body.user.email).toBe('test@example.com');
// Verify email was sent
const sentEmails = await testEmailService.getSentEmails();
expect(sentEmails).toHaveLength(1);
expect(sentEmails[0].to).toBe('test@example.com');
});
});
E2E 测试(Playwright/Cypress):测试完整的用户界面流程。示例:
test('user can complete checkout process', async ({ page }) => {
await page.goto('/products');
await page.click('[data-testid="add-to-cart"]');
await page.click('[data-testid="cart"]');
await page.click('[data-testid="checkout"]');
await page.fill('[name="cardNumber"]', '4242424242424242');
await page.click('[data-testid="complete-order"]');
await expect(page.locator('.success-message')).toBeVisible();
await expect(page).toHaveURL(/\/order-confirmation/);
});
覆盖率验证
实现后检查覆盖率:
npm test -- --coverage
# Output:
# File | % Stmts | % Branch | % Funcs | % Lines
# --------------|---------|----------|---------|--------
# All files | 84.2 | 78.5 | 91.3 | 85.1
要求:语句覆盖率 > 80%,分支覆盖率 > 75%,函数覆盖率 > 85%,行覆盖率 > 80%。
边界情况清单
始终测试:空输入、null/undefined 值、大数据集、并发操作、网络故障、数据库错误、无效数据类型、边界值(0、-1、MAX_INT)、未授权访问、速率限制。
模拟策略
何时模拟:外部 API、数据库调用(单元测试中)、时间相关函数、文件系统操作、第三方服务。
模拟示例:
// Mock external service
vi.mock('./emailService', () => ({
sendEmail: vi.fn().mockResolvedValue({ success: true })
}));
// Mock database
vi.mock('./db', () => ({
users: {
findUnique: vi.fn().mockResolvedValue({ id: 1, name: 'Test' })
}
}));
// Mock Date.now()
vi.spyOn(Date, 'now').mockReturnValue(1234567890000);
测试组织
src/
features/
products/
product.service.ts
product.service.test.ts # Unit tests
product.integration.test.ts # Integration tests
product.e2e.test.ts # E2E tests
调试失败测试
# Run single test file
npm test -- product.service.test.ts
# Run single test
npm test -- -t "calculates discount correctly"
# Run in watch mode
npm test -- --watch
# Run with coverage
npm test -- --coverage --no-cache
集成点
与其他技能互补:verification-loop(提交前验证)、testing-patterns(测试设计模式)、deployment-cicd(CI 测试执行)、security-implementation-guide(安全测试)。
工作流总结
RED:编写失败测试;GREEN:实现最小代码;REFACTOR:在保持测试通过的前提下改进;VERIFY:检查覆盖率是否满足要求;COMMIT:仅在所有测试通过后提交。绝不跳过步骤,绝不提交未经测试的代码。
相关技能
互补技能(配合使用):testing-patterns(单元、集成和 E2E 测试的综合测试模式)、verification-loop(提交前验证工作流,校验所有质量门禁)、deployment-cicd(用于自动化测试执行的 CI 流水线设置)。
替代技能(类似用途):无——TDD 是一种特定方法论,与其他测试方法互补。
前置技能(先学习):testing-patterns(理解测试类型和框架有助于 TDD)。
限制
资料未提供该技能的具体安装方式、支持的编程语言或框架范围、收费模式、平台限制等信息。