DesigningTestsSkill designing-tests

设计和实施任何代码库的测试策略。用于添加测试、提高覆盖率、设置测试基础设施、调试测试失败或当被问及单元测试、集成测试或E2E测试时。

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

设计测试

测试实施工作流程

复制此清单并跟踪进度:

测试实施进度:
- [ ] 第1步:确定测试内容
- [ ] 第2步:选择适当的测试类型
- [ ] 第3步:遵循模板编写测试
- [ ] 第4步:运行测试并验证通过
- [ ] 第5步:检查覆盖率是否达到目标
- [ ] 第6步:修复任何失败的测试

测试金字塔

应用测试金字塔以实现平衡覆盖:

        /\
       /  \     E2E测试(10%)
      /----\    - 关键用户旅程
     /      \   - 速度慢但全面
    /--------\  集成测试(20%)
   /          \ - 组件交互
  /------------\ - API契约
 /              \ 单元测试(70%)
/________________\ - 快速,隔离
                   - 业务逻辑重点

框架选择

JavaScript/TypeScript

类型 推荐 替代
单元 Vitest Jest
集成 Vitest + MSW Jest + SuperTest
E2E Playwright Cypress
组件 测试库 Enzyme

Python

类型 推荐 替代
单元 pytest unittest
集成 pytest + httpx pytest + requests
E2E Playwright Selenium
API pytest + FastAPI TestClient -

Go

类型 推荐
单元 testing + testify
集成 testing + httptest
E2E testing + chromedp

测试结构模板

单元测试

describe('【单元】组件名称', () => {
  describe('方法名称', () => {
    it('应该在[条件]时[预期行为]', () => {
      // 安排
      const input = createTestInput();

      // 行动
      const result = 方法名称(input);

      // 断言
      expect(result).toEqual(expectedOutput);
    });

    it('在[无效条件]时应抛出错误', () => {
      expect(() => 方法名称(invalidInput)).toThrow(ExpectedError);
    });
  });
});

集成测试

describe('【集成】API /users', () => {
  beforeAll(async () => {
    await setupTestDatabase();
  });

  afterAll(async () => {
    await teardownTestDatabase();
  });

  it('应该创建用户并返回201', async () => {
    const response = await request(app)
      .post('/users')
      .send({ name: 'Test', email: 'test@example.com' });

    expect(response.status).toBe(201);
    expect(response.body.id).toBeDefined();
  });
});

E2E测试

describe('【E2E】用户注册流程', () => {
  it('应该成功完成注册', async ({ page }) => {
    await page.goto('/register');

    await page.fill('[data-testid="email"]', 'new@example.com');
    await page.fill('[data-testid="password"]', 'SecurePass123!');
    await page.click('[data-testid="submit"]');

    await expect(page.locator('.welcome-message')).toBeVisible();
    await expect(page).toHaveURL('/dashboard');
  });
});

覆盖率策略

覆盖内容

  • 业务逻辑(100%)
  • 边缘情况和错误处理(90%+)
  • API契约(100%)
  • 关键用户路径(E2E)
  • UI组件(快照+交互)
  • 第三方库内部(不)
  • 简单getter/setter(不)

覆盖率阈值

{
  "coverageThreshold": {
    "global": {
      "branches": 80,
      "functions": 80,
      "lines": 80,
      "statements": 80
    },
    "src/core/": {
      "branches": 95,
      "functions": 95
    }
  }
}

测试数据管理

工厂/构建器

// factories/user.js
export const userFactory = (overrides = {}) => ({
  id: faker.string.uuid(),
  name: faker.person.fullName(),
  email: faker.internet.email(),
  createdAt: new Date(),
  ...overrides,
});

// 使用
const admin = userFactory({ role: 'admin' });

固定装置

// fixtures/users.json
{
  "validUser": { "name": "Test", "email": "test@example.com" },
  "invalidUser": { "name": "", "email": "invalid" }
}

模拟策略

何时模拟

  • 外部API和服务
  • 单元测试中的数据库
  • 确定性的时间/日期
  • 随机值
  • 内部模块(通常)
  • 被测试的代码

模拟示例

// 使用MSW模拟API
import { http, HttpResponse } from 'msw';

export const handlers = [
  http.get('/api/users', () => {
    return HttpResponse.json([
      { id: 1, name: 'John' },
    ]);
  }),
];

// 时间模拟
vi.useFakeTimers();
vi.setSystemTime(new Date('2024-01-01'));

测试验证循环

编写测试后,运行此验证:

测试验证:
- [ ] 所有测试通过:`npm test`
- [ ] 覆盖率满足阈值:`npm test -- --coverage`
- [ ] 无不稳定测试(多次运行)
- [ ] 测试独立(顺序不重要)
- [ ] 测试名称清晰描述行为

如果任何测试失败,请在继续之前修复它们。如果覆盖率低于目标,请为未覆盖的代码路径添加更多测试。

# 运行测试
npm test

# 带覆盖率运行
npm test -- --coverage

# 运行特定测试文件
npm test -- path/to/test.spec.ts

# 开发期间在监视模式下运行
npm test -- --watch