designing-tests

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Designing Tests

测试设计

When to Load

适用场景

  • Trigger: Adding tests, test strategy planning, improving coverage, setting up testing infrastructure
  • Skip: Non-test code changes where testing is not part of the task
  • 触发条件:添加测试、测试策略规划、提升覆盖率、搭建测试基础设施
  • 不适用场景:不涉及测试工作的非测试代码变更

Test Implementation Workflow

测试实现工作流

Copy this checklist and track progress:
Test Implementation Progress:
- [ ] Step 1: Identify what to test
- [ ] Step 2: Select appropriate test type
- [ ] Step 3: Write tests following templates
- [ ] Step 4: Run tests and verify passing
- [ ] Step 5: Check coverage meets targets
- [ ] Step 6: Fix any failing tests
复制以下checklist跟踪进度:
Test Implementation Progress:
- [ ] Step 1: Identify what to test
- [ ] Step 2: Select appropriate test type
- [ ] Step 3: Write tests following templates
- [ ] Step 4: Run tests and verify passing
- [ ] Step 5: Check coverage meets targets
- [ ] Step 6: Fix any failing tests

Testing Pyramid

测试金字塔

Apply the testing pyramid for balanced coverage:
        /\
       /  \     E2E Tests (10%)
      /----\    - Critical user journeys
     /      \   - Slow but comprehensive
    /--------\  Integration Tests (20%)
   /          \ - Component interactions
  /------------\ - API contracts
 /              \ Unit Tests (70%)
/________________\ - Fast, isolated
                   - Business logic focus
遵循测试金字塔原则实现均衡的覆盖率:
        /\
       /  \     E2E Tests (10%)
      /----\    - Critical user journeys
     /      \   - Slow but comprehensive
    /--------\  Integration Tests (20%)
   /          \ - Component interactions
  /------------\ - API contracts
 /              \ Unit Tests (70%)
/________________\ - Fast, isolated
                   - Business logic focus

Framework Selection

测试框架选型

JavaScript/TypeScript

JavaScript/TypeScript

TypeRecommendedAlternative
UnitVitestJest
IntegrationVitest + MSWJest + SuperTest
E2EPlaywrightCypress
ComponentTesting LibraryEnzyme
测试类型推荐方案替代方案
单元测试VitestJest
集成测试Vitest + MSWJest + SuperTest
E2E测试PlaywrightCypress
组件测试Testing LibraryEnzyme

Python

Python

TypeRecommendedAlternative
Unitpytestunittest
Integrationpytest + httpxpytest + requests
E2EPlaywrightSelenium
APIpytest + FastAPI TestClient-
测试类型推荐方案替代方案
单元测试pytestunittest
集成测试pytest + httpxpytest + requests
E2E测试PlaywrightSelenium
API测试pytest + FastAPI TestClient-

Go

Go

TypeRecommended
Unittesting + testify
Integrationtesting + httptest
E2Etesting + chromedp
测试类型推荐方案
单元测试testing + testify
集成测试testing + httptest
E2E测试testing + chromedp

Test Structure Templates

测试结构模板

Unit Test

单元测试模板

javascript
describe("[Unit] ComponentName", () => {
  describe("methodName", () => {
    it("should [expected behavior] when [condition]", () => {
      // Arrange
      const input = createTestInput();

      // Act
      const result = methodName(input);

      // Assert
      expect(result).toEqual(expectedOutput);
    });

    it("should throw error when [invalid condition]", () => {
      expect(() => methodName(invalidInput)).toThrow(ExpectedError);
    });
  });
});
javascript
describe("[Unit] ComponentName", () => {
  describe("methodName", () => {
    it("should [expected behavior] when [condition]", () => {
      // Arrange
      const input = createTestInput();

      // Act
      const result = methodName(input);

      // Assert
      expect(result).toEqual(expectedOutput);
    });

    it("should throw error when [invalid condition]", () => {
      expect(() => methodName(invalidInput)).toThrow(ExpectedError);
    });
  });
});

Integration Test

集成测试模板

javascript
describe("[Integration] API /users", () => {
  beforeAll(async () => {
    await setupTestDatabase();
  });

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

  it("should create user and return 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();
  });
});
javascript
describe("[Integration] API /users", () => {
  beforeAll(async () => {
    await setupTestDatabase();
  });

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

  it("should create user and return 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 Test

E2E测试模板

javascript
describe("[E2E] User Registration Flow", () => {
  it("should complete registration successfully", 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");
  });
});
javascript
describe("[E2E] User Registration Flow", () => {
  it("should complete registration successfully", 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");
  });
});

Coverage Strategy

覆盖率策略

What to Cover

需要覆盖的范围

  • ✅ Business logic (100%)
  • ✅ Edge cases and error handling (90%+)
  • ✅ API contracts (100%)
  • ✅ Critical user paths (E2E)
  • ⚠️ UI components (snapshot + interaction)
  • ❌ Third-party library internals
  • ❌ Simple getters/setters
  • ✅ 业务逻辑 (100%)
  • ✅ 边界场景与错误处理 (90%+)
  • ✅ API契约 (100%)
  • ✅ 核心用户路径 (E2E)
  • ⚠️ UI组件 (快照 + 交互测试)
  • ❌ 第三方库内部逻辑
  • ❌ 简单的getter/setter方法

Coverage Thresholds

覆盖率阈值配置

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

Test Data Management

测试数据管理

Factories/Builders

工厂/构造器

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

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

// Usage
const admin = userFactory({ role: "admin" });

Fixtures

固定测试数据(Fixtures)

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

Mocking Strategy

Mock策略

When to Mock

适用Mock的场景

  • ✅ External APIs and services
  • ✅ Database in unit tests
  • ✅ Time/Date for determinism
  • ✅ Random values
  • ❌ Internal modules (usually)
  • ❌ The code under test
  • ✅ 外部API与服务
  • ✅ 单元测试中的数据库
  • ✅ 用于保证确定性的时间/日期
  • ✅ 随机值
  • ❌ 内部模块(通常不需要)
  • ❌ 被测试的代码本身

Mock Examples

Mock示例

javascript
// API mocking with MSW
import { http, HttpResponse } from "msw";

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

// Time mocking
vi.useFakeTimers();
vi.setSystemTime(new Date("2024-01-01"));
javascript
// API mocking with MSW
import { http, HttpResponse } from "msw";

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

// Time mocking
vi.useFakeTimers();
vi.setSystemTime(new Date("2024-01-01"));

Test Validation Loop

测试验证流程

After writing tests, run this validation:
Test Validation:
- [ ] All tests pass: `npm test`
- [ ] Coverage meets thresholds: `npm test -- --coverage`
- [ ] No flaky tests (run multiple times)
- [ ] Tests are independent (order doesn't matter)
- [ ] Test names clearly describe behavior
If any tests fail, fix them before proceeding. If coverage is below target, add more tests for uncovered code paths.
bash
undefined
编写完测试后,按以下步骤验证:
Test Validation:
- [ ] All tests pass: `npm test`
- [ ] Coverage meets thresholds: `npm test -- --coverage`
- [ ] No flaky tests (run multiple times)
- [ ] Tests are independent (order doesn't matter)
- [ ] Test names clearly describe behavior
如果有测试失败,请先修复再继续。如果覆盖率低于目标,请为未覆盖的代码路径补充更多测试。
bash
undefined

Run tests

Run tests

npm test
npm test

Run with coverage

Run with coverage

npm test -- --coverage
npm test -- --coverage

Run specific test file

Run specific test file

npm test -- path/to/test.spec.ts
npm test -- path/to/test.spec.ts

Run in watch mode during development

Run in watch mode during development

npm test -- --watch
undefined
npm test -- --watch
undefined