测试驱动开发工作流 tdd-workflow

测试驱动开发工作流是一种软件开发方法论,强调先编写测试后编写代码,以确保代码质量和全面覆盖。它遵循红-绿-重构循环,涵盖单元测试、集成测试和端到端测试,帮助开发者减少bug、提高可维护性。关键词:测试驱动开发、TDD、测试覆盖、红绿重构、软件开发、代码质量、单元测试、集成测试、E2E测试。

测试 0 次安装 0 次浏览 更新于 3/7/2026

名称: tdd-workflow 描述: 具有全面覆盖要求的测试驱动开发工作流,包括单元、集成和端到端测试 许可证: MIT 复杂度: 中级 学习时间: 30分钟 先决条件:

  • testing-patterns 标签:
  • tdd
  • test-driven-development
  • red-green-refactor
  • coverage
  • quality 输入:
  • 功能需求
  • 源代码 输出:
  • 测试套件
  • 实现代码 副作用:
  • 创建文件
  • 运行命令 触发器:
  • 用户询问关于TDD
  • 用户询问关于测试
  • 文件类型:*.test.ts
  • 文件类型:*.spec.py 互补:
  • testing-patterns
  • verification-loop 层级: 核心 元数据: 来源: affaan-m/everything-claude-code 改编者: ai-skills 类别: 开发工作流

测试驱动开发工作流

强制执行测试驱动开发原则,实现所有层面的全面测试覆盖。

何时激活

  • 编写新功能
  • 修复bug或问题
  • 重构现有代码
  • 添加API端点
  • 创建新组件
  • 实现业务逻辑

核心原则

1. 测试先于代码

始终先写测试,然后实现代码使测试通过。没有例外。

2. 覆盖要求

  • 最低80%覆盖(单元 + 集成 + E2E)
  • 覆盖所有边界情况
  • 测试错误场景
  • 验证边界条件
  • 快乐路径和悲伤路径

3. 测试金字塔

        ┌────────┐
        │   E2E  │  (10-20%)
        ├────────┤
        │  集成  │  (20-30%)
        ├────────┤
        │  单元  │  (50-70%)
        └────────┘

TDD工作流:红-绿-重构

步骤1: 红 - 编写失败的测试

从用户故事开始:

作为[角色],我想要[操作],以便[好处]

示例:
作为用户,我想要按类别搜索产品,
以便我能快速找到相关商品。

编写测试:

describe('产品搜索', () => {
  it('返回按类别过滤的产品', async () => {
    const products = await searchProducts({ category: 'electronics' });
    
    expect(products).toHaveLength(5);
    expect(products.every(p => p.category === 'electronics')).toBe(true);
  });
});

步骤2: 运行测试(它们应该失败)

npm test
# ✗ 产品搜索 > 返回按类别过滤的产品
#   TypeError: searchProducts 不是一个函数

这是好的! 红阶段确认测试在工作。

步骤3: 绿 - 实现最小代码

编写刚好足够通过的代码:

export async function searchProducts(filters: SearchFilters) {
  const { category } = filters;
  return db.products.findMany({
    where: { category }
  });
}

步骤4: 运行测试(它们应该通过)

npm test
# ✓ 产品搜索 > 返回按类别过滤的产品 (42ms)

步骤5: 重构 - 改进代码

现在重构,同时保持测试通过:

export async function searchProducts(filters: SearchFilters) {
  const query = buildSearchQuery(filters);
  const results = await executeSearch(query);
  return transformResults(results);
}

再次运行测试以确保它们仍然通过。

测试类型

单元测试

目的:在隔离中测试单个函数

describe('calculateDiscount', () => {
  it('为基本层级应用10%折扣', () => {
    const price = calculateDiscount(100, 'basic');
    expect(price).toBe(90);
  });

  it('为高级层级应用20%折扣', () => {
    const price = calculateDiscount(100, 'premium');
    expect(price).toBe(80);
  });

  it('为无效层级抛出错误', () => {
    expect(() => calculateDiscount(100, 'invalid')).toThrow();
  });
});

集成测试

目的:测试多个组件协同工作

describe('用户注册API', () => {
  it('创建用户并发送欢迎邮件', 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');
    
    // 验证邮件已发送
    const sentEmails = await testEmailService.getSentEmails();
    expect(sentEmails).toHaveLength(1);
    expect(sentEmails[0].to).toBe('test@example.com');
  });
});

端到端测试(Playwright/Cypress)

目的:通过UI测试完整的用户流程

test('用户可以完成结账流程', 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

# 输出:
# 文件          | % 语句 | % 分支 | % 函数 | % 行
# --------------|---------|----------|---------|--------
# 所有文件     |   84.2  |   78.5   |   91.3  |   85.1

要求

  • 语句: > 80%
  • 分支: > 75%
  • 函数: > 85%
  • 行: > 80%

边界情况清单

始终测试:

  • [ ] 空输入
  • [ ] 空值/未定义值
  • [ ] 大数据集
  • [ ] 并发操作
  • [ ] 网络故障
  • [ ] 数据库错误
  • [ ] 无效数据类型
  • [ ] 边界值(0, -1, MAX_INT)
  • [ ] 未授权访问
  • [ ] 速率限制

模拟策略

何时模拟

  • 外部API
  • 数据库调用(在单元测试中)
  • 时间依赖函数
  • 文件系统操作
  • 第三方服务

示例模拟

// 模拟外部服务
vi.mock('./emailService', () => ({
  sendEmail: vi.fn().mockResolvedValue({ success: true })
}));

// 模拟数据库
vi.mock('./db', () => ({
  users: {
    findUnique: vi.fn().mockResolvedValue({ id: 1, name: '测试' })
  }
}));

// 模拟 Date.now()
vi.spyOn(Date, 'now').mockReturnValue(1234567890000);

测试组织

src/
  特性/
    产品/
      product.service.ts
      product.service.test.ts      # 单元测试
      product.integration.test.ts  # 集成测试
      product.e2e.test.ts          # E2E测试

调试失败的测试

# 运行单个测试文件
npm test -- product.service.test.ts

# 运行单个测试
npm test -- -t "正确计算折扣"

# 在监视模式下运行
npm test -- --watch

# 运行带覆盖
npm test -- --coverage --no-cache

集成点

互补:

  • verification-loop:用于预提交验证
  • testing-patterns:用于测试设计模式
  • deployment-cicd:用于CI测试执行
  • security-implementation-guide:用于安全测试

工作流总结

  1. :编写失败的测试
  2. 绿:实现最小代码
  3. 重构:改进同时保持测试通过
  4. 验证:检查覆盖是否满足要求
  5. 提交:仅在所有测试通过后提交

永不跳过步骤。永不提交未测试的代码。


相关技能

互补技能(一起使用)

替代技能(相似目的)

  • 无 - TDD是特定方法论,补充其他测试方法

先决技能(先学习)