零度AI
高级18 分钟阅读

Claude Code 测试最佳实践

使用 Claude Code 编写测试、测试驱动开发、持续测试的完整指南

Claude Code测试TDD单元测试集成测试

测试最佳实践概述

测试是保障代码质量的重要手段,Claude Code 可以帮你高效编写测试。

测试金字塔

单元测试 → 集成测试 → E2E 测试,底层测试越多,上层测试越少。

测试类型

测试金字塔

测试金字塔: /\ /E2E\ 少量 E2E 测试 /------\ /集成测试\ 中等集成测试 /----------\ / 单元测试 \ 大量单元测试 /------------\ 比例:70% 单元测试,20% 集成测试,10% E2E 测试

各层测试特点

| 类型 | 测试对象 | 特点 | 速度 | |------|----------|------|------| | 单元测试 | 函数/方法 | 隔离、快速 | < 1ms | | 集成测试 | 模块交互 | 涉及数据库 | < 100ms | | E2E 测试 | 完整流程 | 模拟用户 | < 1s |

Claude Code 测试生成

生成单元测试

bash
# Claude Code 生成单元测试
claude --generate-tests --unit src/utils/validator.ts

输出示例

typescript
// src/utils/validator.test.ts

import { describe, it, expect } from 'vitest';
import { validateEmail, validatePassword } from './validator';

describe('validateEmail', () => {
  it('应该接受有效的邮箱格式', () => {
    expect(validateEmail('test@example.com')).toBe(true);
    expect(validateEmail('user.name@domain.co')).toBe(true);
  });

  it('应该拒绝无效的邮箱格式', () => {
    expect(validateEmail('invalid')).toBe(false);
    expect(validateEmail('@domain.com')).toBe(false);
    expect(validateEmail('user@')).toBe(false);
  });
});

describe('validatePassword', () => {
  it('应该接受符合要求的密码', () => {
    expect(validatePassword('Password123!')).toBe(true);
    expect(validatePassword('MyP@ssw0rd')).toBe(true);
  });

  it('应该拒绝太短的密码', () => {
    expect(validatePassword('Pas1!')).toBe(false);
    expect(validatePassword('Ab1!')).toBe(false);
  });

  it('应该拒绝没有特殊字符的密码', () => {
    expect(validatePassword('Password123')).toBe(false);
  });
});

TDD 开发模式

TDD 流程

TDD 红-绿-重构循环: 1. 红(Red) → 写一个失败的测试 2. 绿(Green)→ 写最简单的代码让测试通过 3. 重构(Refactor)→ 优化代码,保持测试通过

TDD 示例

bash
# TDD 开发一个计算器
claude --tdd --create calculator

# 输出示例
## 1. 红:先写测试

describe('Calculator', () => {
  it('应该正确执行加法', () => {
    const calc = new Calculator();
    expect(calc.add(2, 3)).toBe(5);
  });

  it('应该正确执行减法', () => {
    const calc = new Calculator();
    expect(calc.subtract(5, 3)).toBe(2);
  });
});

## 2. 绿:写最简单的实现

class Calculator {
  add(a, b) {
    return a + b;
  }

  subtract(a, b) {
    return a - b;
  }
}

## 3. 重构:优化代码

class Calculator {
  operate(a, b, operator) {
    const operations = {
      '+': (a, b) => a + b,
      '-': (a, b) => a - b,
    };
    return operations[operator]?.(a, b) ?? NaN;
  }
}

测试覆盖

覆盖报告

bash
# 生成测试覆盖报告
claude --coverage --report

# 输出示例
## 测试覆盖报告

| 文件 | 行覆盖 | 分支覆盖 | 函数覆盖 |
|------|--------|----------|----------|
| src/utils/validator.ts | 95% | 88% | 100% |
| src/utils/format.ts | 82% | 65% | 100% |
| src/services/user.ts | 70% | 55% | 100% |

## 未覆盖的代码
src/utils/format.ts:24-26
src/services/user.ts:45-48

提高覆盖率的策略

typescript
// 1. 测试边界条件
it('应该处理空数组', () => {
  expect(sum([])).toBe(0);
});

it('应该处理极大数', () => {
  expect(sum([Number.MAX_SAFE_INTEGER, 1])).toBe(Number.MAX_SAFE_INTEGER);
});

// 2. 测试错误情况
it('应该抛出预期错误', () => {
  expect(() => parseJSON('invalid')).toThrow(SyntaxError);
});

// 3. 测试 null/undefined
it('应该处理 null 输入', () => {
  expect(processValue(null)).toBeNull();
});

Mock 与 Stub

Jest Mock

typescript
// Mock 函数
const mockFn = vi.fn();

mockFn.mockReturnValue('result');
mockFn.mockImplementation((input) => input * 2);

// Mock 模块
vi.mock('./api', () => ({
  fetchUser: vi.fn(),
}));

// Mock 定时器
vi.useFakeTimers();
vi.advanceTimersByTime(1000);

Stub 示例

typescript
// Stub 服务依赖
const mockUserService = {
  getUserById: vi.fn().mockResolvedValue({ id: '1', name: 'Test' }),
  createUser: vi.fn().mockResolvedValue({ id: '2' }),
};

const service = new UserService(mockUserService);

集成测试

API 集成测试

typescript
// tests/api/user.api.test.ts
import { describe, it, expect, beforeAll } from 'vitest';
import supertest from 'supertest';
import { app } from '../../app';

describe('POST /api/users', () => {
  beforeAll(async () => {
    await resetDatabase();
  });

  it('应该成功创建用户', async () => {
    const response = await supertest(app)
      .post('/api/users')
      .send({
        username: 'testuser',
        email: 'test@example.com',
        password: 'Password123!',
      })
      .expect(201);

    expect(response.body.success).toBe(true);
    expect(response.body.data.username).toBe('testuser');
  });

  it('应该验证邮箱格式', async () => {
    await supertest(app)
      .post('/api/users')
      .send({
        username: 'testuser',
        email: 'invalid-email',
        password: 'Password123!',
      })
      .expect(400);
  });
});

持续集成

CI 测试配置

yaml
# .github/workflows/test.yml
name: Test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run lint
        run: npm run lint

      - name: Run tests
        run: npm run test:coverage

      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/lcov.info

测试最佳实践清单

✅ 测试应该: - 快速(毫秒级) - 独立(不依赖其他测试) - 可重复(结果一致) - 真实(测试真实行为) - 清晰(测试名称描述意图) ❌ 测试不应该: - 依赖执行顺序 - 共享可变状态 - 访问网络或数据库(集成测试除外) - 测试实现细节而非行为

测试价值

好的测试让你有信心重构,有信心发布,有信心创新。

总结

Claude Code 测试最佳实践:

  1. 测试金字塔:底层测试多,上层测试少
  2. TDD:红-绿-重构循环
  3. 覆盖率:目标 80%+ 行覆盖
  4. Mock:隔离依赖
  5. CI:自动化测试
  6. 最佳实践:快速、独立、可重复

记住:没有测试的代码是有缺陷的代码