full-coverage

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Full Coverage — Test Generation

全覆盖率——测试生成

Generate the right tests for every layer of the testing pyramid: unit, integration, API, and E2E. The skill analyzes the code, selects the correct layers, and implements each one following strict guidelines.
为测试金字塔的每一层生成合适的测试:单元、集成、API和E2E。本技能会分析代码,选择正确的测试层,并遵循严格的规范实现每一层的测试。

Testing Pyramid

测试金字塔

        ╔═══════════════════════╗
        ║    E2E Tests          ║  Playwright browser · user journeys
        ╠═══════════════════════╣
        ║  API Tests            ║  Playwright HTTP · HTTP contracts
        ╠═══════════════════════╣
        ║Integration            ║  Vitest + Prisma · every branch with real DB
        ╠═══════════════════════╣
        ║  Unit Tests           ║  Vitest · isolated logic, no I/O
        ╚═══════════════════════╝
        ╔═══════════════════════╗
        ║    E2E Tests          ║  Playwright browser · user journeys
        ╠═══════════════════════╣
        ║  API Tests            ║  Playwright HTTP · HTTP contracts
        ╠═══════════════════════╣
        ║Integration            ║  Vitest + Prisma · every branch with real DB
        ╠═══════════════════════╣
        ║  Unit Tests           ║  Vitest · isolated logic, no I/O
        ╚═══════════════════════╝

Layer Responsibility Matrix

层职责矩阵

Each concern is owned by exactly one layer. Do not duplicate responsibilities.
ConcernUnitIntegrationAPIE2E
Zod field exhaustive validationOwner1–2 wiring checks1 per endpointNo
Service method branchesOwner (mocked deps)Owner (real DB)NoNo
Pure utility functionsOwnerNoNoNo
Mock call argument verificationOwnerNoNoNo
HTTP contract (status codes, body)NoNoOwnerNo
Write verification (POST→GET, DELETE→404)NoNoOwnerNo
Authorization enforcement (401, 403)NoOwnerOwnerNo
External service calls (mocked)Owner (vi.mock)Owner (Wiremock)NoNo
DB persistence verificationNoOwnerNoNo
Complete user journey through UINoNoNoOwner
Navigation and routingNoNoNoOwner

每个测试点仅归属一个测试层,不要重复覆盖职责。
测试点单元测试集成测试API测试E2E测试
Zod字段全量校验责任层1-2项连通性检查每个接口1项检查
服务方法分支责任层(依赖mock)责任层(真实数据库)
纯工具函数责任层
Mock调用参数校验责任层
HTTP契约(状态码、响应体)责任层
写入操作校验(POST→GET、DELETE→404)责任层
鉴权规则校验(401、403)责任层责任层
外部服务调用(mock)责任层(vi.mock)责任层(Wiremock)
数据库持久化校验责任层
完整UI用户流程责任层
导航与路由责任层

Step 1: Analyze the Code

步骤1:分析代码

Before selecting layers or writing any tests, read the target code.
Read these files:
  • Zod schemas / DTOs (
    <domain>.dto.ts
    )
  • Service class (
    <domain>.service.ts
    )
  • Route handlers (
    app/api/<path>/route.ts
    )
  • Utility functions (
    <domain>.utils.ts
    )
  • DB schema (
    prisma/schema.prisma
    )
  • Error definitions (
    src/lib/server/errors.ts
    )
  • External service clients (if any)
  • UI components / pages (if any — look for
    data-testid
    attributes)
Build an inventory:
  • Schemas found: list field names and rules
  • Service methods found: list method names and their dependencies
  • HTTP endpoints found: list METHOD /path
  • Utility functions found: list exported functions
  • External service calls found: list service names
  • UI pages found: list page URLs
Write a one-paragraph summary: "This module has X schemas, Y service methods, Z endpoints... Recommended layers: [list]."

在选择测试层或编写任何测试之前,先读取目标代码。
读取以下文件:
  • Zod模式 / DTO(
    <domain>.dto.ts
  • 服务类(
    <domain>.service.ts
  • 路由处理函数(
    app/api/<path>/route.ts
  • 工具函数(
    <domain>.utils.ts
  • 数据库模式(
    prisma/schema.prisma
  • 错误定义(
    src/lib/server/errors.ts
  • 外部服务客户端(如有)
  • UI组件/页面(如有——查找
    data-testid
    属性)
梳理资产清单:
  • 找到的模式:列出字段名和校验规则
  • 找到的服务方法:列出方法名及其依赖
  • 找到的HTTP接口:列出 请求方法 / 路径
  • 找到的工具函数:列出导出的函数
  • 找到的外部服务调用:列出服务名
  • 找到的UI页面:列出页面URL
编写一段摘要:"本模块包含X个模式、Y个服务方法、Z个接口... 推荐测试层:[列表]。"

Step 2: Select Layers

步骤2:选择测试层

Apply this decision tree after completing Step 1:
Does the code have Zod schemas or pure utility functions?
  YES → Unit tests required (always the baseline layer)

Does the code have service methods with branches (if/else, switch, throw)?
  YES → Unit tests (mocked) + Integration tests (real DB) required
  Why: unit tests prove logic; integration tests prove wiring with real DB.
        Together they are not redundant — they cover different failure modes.

Does the code expose HTTP endpoints?
  YES → API tests required (one spec file per endpoint)

Does the code have browser UI with data-testid attributes?
  YES → E2E tests required (one spec per feature area)
Common combinations:
  • Pure utility library → Unit only
  • Backend service, no UI → Unit + Integration + API (if endpoints exist)
  • Full-stack feature → All four layers
State explicitly which layers are selected and which are skipped with a reason: "Skipping E2E: no browser UI found in this module."

完成步骤1后按照以下决策树选择测试层:
代码是否包含Zod模式或纯工具函数?
  是 → 必须编写单元测试(始终是基础层)

代码是否包含带分支逻辑的服务方法(if/else、switch、throw)?
  是 → 必须编写单元测试(依赖mock)+ 集成测试(真实数据库)
  原因:单元测试验证逻辑正确性;集成测试验证与真实数据库的连通性。
        两者并不冗余——覆盖的故障模式不同。

代码是否暴露HTTP接口?
  是 → 必须编写API测试(每个接口对应一个测试用例文件)

代码是否包含带`data-testid`属性的浏览器UI?
  是 → 必须编写E2E测试(每个功能域对应一个测试用例文件)
常见组合:
  • 纯工具库 → 仅单元测试
  • 无UI的后端服务 → 单元 + 集成 + API测试(如果有接口)
  • 全栈功能 → 全部四层测试
明确说明选择了哪些测试层、跳过了哪些层并给出原因: "跳过E2E测试:本模块中未找到浏览器UI。"

Step 3: Generate Tests, Layer by Layer

步骤3:逐层生成测试

Work bottom-up. Generate unit tests first, then integration, then API, then E2E. Complete and self-validate each layer before moving to the next.
自底向上工作。先生成单元测试,然后是集成、API,最后是E2E测试。每一层完成并自校验后再进入下一层。

If Unit tests are selected:

如果选择了单元测试:

Read
references/unit-testing.md
before writing any code.
Key steps:
  1. Read schemas, service, utils, errors
  2. Map every field × rule and every service branch as a case tree (write as comments first)
  3. Create
    schema.helper.ts
    and
    <domain>.unit-factory.ts
  4. Write schema tests (one
    describe
    per field, one
    it()
    per rule)
  5. Write service tests (all branches mocked, exact mock argument verification)
  6. Write utility tests (if applicable)
  7. Run:
    vitest run src/modules/<domain>/test/unit/
  8. Run self-validation checklist from the reference file
编写代码前先阅读
references/unit-testing.md
关键步骤:
  1. 读取模式、服务、工具、错误定义
  2. 将每个字段×规则、每个服务分支映射为用例树(先写为注释)
  3. 创建
    schema.helper.ts
    <domain>.unit-factory.ts
  4. 编写模式测试(每个字段对应一个
    describe
    块,每条规则对应一个
    it()
    用例)
  5. 编写服务测试(所有分支依赖mock,严格校验mock调用参数)
  6. 编写工具测试(如有)
  7. 运行:
    vitest run src/modules/<domain>/test/unit/
  8. 运行参考文件中的自校验检查清单

If Integration tests are selected:

如果选择了集成测试:

Read
references/integration-testing.md
before writing any code.
Key steps:
  1. Read source + auth implementation + error response shape (determines assertion format)
  2. List every execution path as comments inside
    describe
    blocks
  3. Create
    DatabaseHelper
    ,
    AuthHelper
    , fixtures, api-utils
  4. Write handler tests (1–2 validation wiring tests per endpoint — no exhaustive Zod rules)
  5. Write service layer tests (direct calls, real DB)
  6. Run:
    yarn test:integration
    (or equivalent)
  7. Run self-validation checklist from the reference file
编写代码前先阅读
references/integration-testing.md
关键步骤:
  1. 读取源代码 + 鉴权实现 + 错误响应格式(决定断言格式)
  2. describe
    块内将所有执行路径列为注释
  3. 创建
    DatabaseHelper
    AuthHelper
    、fixtures、api-utils
  4. 编写处理函数测试(每个接口1-2项校验连通性测试——不做全量Zod规则校验)
  5. 编写服务层测试(直接调用,真实数据库)
  6. 运行:
    yarn test:integration
    (或等效命令)
  7. 运行参考文件中的自校验检查清单

If API tests are selected:

如果选择了API测试:

Read
references/api-testing.md
before writing any code.
Key steps:
  1. Read route handlers, DTOs, error definitions
  2. Verify/create response helpers for all error codes
  3. Create test-owned factory (never import backend DTOs)
  4. Create API utilities (one function per endpoint)
  5. Create cleanup utilities
  6. Write test specs: plan scenarios as comments first, then implement
  7. Run:
    npx playwright test --project=api
  8. Run self-validation checklist from the reference file
编写代码前先阅读
references/api-testing.md
关键步骤:
  1. 读取路由处理函数、DTO、错误定义
  2. 验证/创建所有错误码的响应辅助工具
  3. 创建测试专属工厂函数(不要导入后端DTO)
  4. 创建API工具(每个接口对应一个函数)
  5. 创建清理工具
  6. 编写测试用例:先将场景规划为注释,再实现
  7. 运行:
    npx playwright test --project=api
  8. 运行参考文件中的自校验检查清单

If E2E tests are selected:

如果选择了E2E测试:

Read
references/e2e-testing.md
before writing any code.
Key steps:
  1. Read PRD, page components (
    data-testid
    attributes), existing fixtures
  2. Identify user flows (one spec file per feature area)
  3. Create or update Page Object Models (locators via
    data-testid
    only)
  4. Create test data factory with
    counter + timestamp + random
    pattern
  5. Create API-based setup helper and cleanup helper
  6. Write test specs (API setup, inject auth, navigate, UI interaction, assert)
  7. Run:
    npx playwright test --project=chromium
  8. Run self-validation checklist from the reference file

编写代码前先阅读
references/e2e-testing.md
关键步骤:
  1. 读取PRD、页面组件(
    data-testid
    属性)、现有fixtures
  2. 识别用户流程(每个功能域对应一个测试用例文件)
  3. 创建或更新页面对象模型(仅通过
    data-testid
    定位元素)
  4. 用「计数器 + 时间戳 + 随机数」模式创建测试数据工厂
  5. 创建基于API的设置辅助工具和清理辅助工具
  6. 编写测试用例(API设置、注入鉴权、导航、UI交互、断言)
  7. 运行:
    npx playwright test --project=chromium
  8. 运行参考文件中的自校验检查清单

Universal Patterns

通用规范

These apply at every layer. Do not repeat in reference files.
这些规范适用于所有测试层,无需在参考文件中重复。

Unique test data

唯一测试数据

typescript
let counter = 0;
function uniqueSuffix(): string {
  counter++;
  return `${counter}-${Date.now()}-${Math.floor(Math.random() * 100000)}`;
}
// Usage: `test-user-${uniqueSuffix()}@test.com`
Why: parallel test runs share a database. Non-unique data causes false failures when one test's cleanup deletes another test's records.
typescript
let counter = 0;
function uniqueSuffix(): string {
  counter++;
  return `${counter}-${Date.now()}-${Math.floor(Math.random() * 100000)}`;
}
// 用法:`test-user-${uniqueSuffix()}@test.com`
原因:并行测试运行会共享数据库。如果数据不唯一,当一个测试的清理操作删除了另一个测试的记录时,会导致误报失败。

Arrange-Act-Assert

安排-执行-断言

Every test follows this exact structure:
typescript
// Arrange — set up state
const cookie = await authenticateUser(request);
const dto = generateCreateNoteDto();

// Act — execute the behavior
const response = await executePostNoteRequest(request, dto, cookie);

// Assert — verify the result
expect201Created(response);
expect(response.data.title).toBe(dto.title);
每个测试都遵循以下严格结构:
typescript
// 安排 — 设置状态
const cookie = await authenticateUser(request);
const dto = generateCreateNoteDto();

// 执行 — 运行目标行为
const response = await executePostNoteRequest(request, dto, cookie);

// 断言 — 验证结果
expect201Created(response);
expect(response.data.title).toBe(dto.title);

Cleanup in afterEach

在afterEach中做清理

typescript
// ✓ Correct — runs even when test throws
test.afterEach(async ({ request }) => {
  for (const cookie of cookiesToCleanup) {
    await cleanupNotes(request, cookie);
    await cleanupUser(request, cookie);
  }
  cookiesToCleanup.length = 0;
});

// ✗ Wrong — skipped when test throws before reaching cleanup
test("...", async ({ request }) => {
  const cookie = await authenticateUser(request);
  // ...
  await cleanupUser(request, cookie); // This line may never run
});
typescript
// ✓ 正确 — 即使测试抛出异常也会运行
test.afterEach(async ({ request }) => {
  for (const cookie of cookiesToCleanup) {
    await cleanupNotes(request, cookie);
    await cleanupUser(request, cookie);
  }
  cookiesToCleanup.length = 0;
});

// ✗ 错误 — 当测试在到达清理代码前抛出异常时会跳过清理
test("...", async ({ request }) => {
  const cookie = await authenticateUser(request);
  // ...
  await cleanupUser(request, cookie); // 这行可能永远不会运行
});

No shared state between tests

测试之间无共享状态

  • No
    beforeAll
    for shared data
  • No shared auth sessions
  • Each test creates its own user and test entities
  • 不要用
    beforeAll
    创建共享数据
  • 不要共享鉴权会话
  • 每个测试都创建自己的用户和测试实体

No static waits

不要使用静态等待

typescript
// ✗ Forbidden at all layers
await new Promise(resolve => setTimeout(resolve, 1000));
await page.waitForTimeout(5000);

// ✓ Use explicit conditions instead
// API/Integration: poll with 400ms interval, 15s timeout
// E2E: locator.waitFor(), page.waitForURL(), expect(locator).toBeVisible()
typescript
// ✗ 所有层都禁止使用
await new Promise(resolve => setTimeout(resolve, 1000));
await page.waitForTimeout(5000);

// ✓ 改用显式条件
// API/集成测试:间隔400ms轮询,超时时间15s
// E2E测试:locator.waitFor(), page.waitForURL(), expect(locator).toBeVisible()

No snapshot tests

不要使用快照测试

.toMatchSnapshot()
and
.toMatchInlineSnapshot()
are forbidden at all layers. Snapshots hide intent and produce opaque diffs.
所有层都禁止使用
.toMatchSnapshot()
.toMatchInlineSnapshot()
。快照会隐藏测试意图,且生成的差异不透明。

No hardcoded URLs

不要硬编码URL

Always use relative paths. Playwright's
baseURL
from config handles environment switching.

始终使用相对路径。Playwright配置中的
baseURL
会处理环境切换。

Reference File Guide

参考文件指南

When generating tests for a layer, read the corresponding reference file first. Each file includes the full workflow, verbatim templates, and a self-validation checklist.
FileContainsKey templates
references/unit-testing.md
8-step workflow, Zod test patterns, mocking rules
schema.helper.ts
, unit factory, service test structure
references/integration-testing.md
5-step workflow, parallel-safe cleanup, validation wiring
DatabaseHelper
,
AuthHelper
(both variants), fixture structure
references/api-testing.md
8-step workflow, test-owned interfaces, write verification
authenticateUser()
, API utilities, response helpers, per-endpoint test counts
references/e2e-testing.md
9-step workflow, POM rules, waiting strategy
createUserViaApi()
,
injectAuthCookie()
, Page Object Model, 5 wait patterns

为某一层生成测试时,先阅读对应的参考文件。每个文件都包含完整工作流、可直接使用的模板和自校验检查清单。
文件包含内容核心模板
references/unit-testing.md
8步工作流、Zod测试模式、mock规则
schema.helper.ts
、单元工厂、服务测试结构
references/integration-testing.md
5步工作流、并行安全清理、校验连通性
DatabaseHelper
AuthHelper
(两种变体)、fixture结构
references/api-testing.md
8步工作流、测试专属接口、写入校验
authenticateUser()
、API工具、响应辅助工具、单接口测试数量规范
references/e2e-testing.md
9步工作流、POM规则、等待策略
createUserViaApi()
injectAuthCookie()
、页面对象模型、5种等待模式

Cross-Layer Checklist

跨层检查清单

After all layers are complete, verify the pyramid is correctly shaped:
No layer duplication:
  • Unit tests cover Zod field validation exhaustively — integration/API/E2E do not
  • Integration tests have only 1–2 validation wiring tests per endpoint
  • API tests have only 1 validation test per endpoint
  • E2E tests cover user journeys and navigation — no field validation
Pyramid shape (count tests per layer):
  • Unit tests cover the most cases — exhaustive per field and per branch
  • Integration tests are fewer — only real DB wiring and auth paths
  • API tests are fewer still — one spec per endpoint
  • E2E tests are the fewest — one spec per user journey
All self-validation checklists were run:
  • Unit layer checklist ✓
  • Integration layer checklist ✓
  • API layer checklist ✓
  • E2E layer checklist ✓

所有层完成后,验证测试金字塔的结构是否正确:
无层间重复覆盖:
  • 单元测试全量覆盖Zod字段校验 —— 集成/API/E2E测试不覆盖
  • 集成测试每个接口仅做1-2项校验连通性测试
  • API测试每个接口仅做1项校验测试
  • E2E测试覆盖用户流程和导航 —— 不做字段校验
金字塔结构(每层测试数量):
  • 单元测试覆盖最多场景 —— 全量覆盖每个字段和每个分支
  • 集成测试数量更少 —— 仅覆盖真实数据库连通性和鉴权路径
  • API测试数量更少 —— 每个接口对应一个测试用例
  • E2E测试数量最少 —— 每个用户流程对应一个测试用例
所有自校验检查清单都已运行:
  • 单元层检查清单 ✓
  • 集成层检查清单 ✓
  • API层检查清单 ✓
  • E2E层检查清单 ✓

Cross-Layer Examples

跨层示例

The same "notes" domain — showing exactly how coverage is divided, not duplicated.
以相同的「笔记」域为例——明确展示覆盖率如何拆分,而非重复覆盖。

Testing a
title
field (min 1, max 255, required)

测试
title
字段(最小长度1,最大长度255,必填)

LayerWhat to testTest count
Unitmissing, undefined, null, empty string, min boundary (1 char ✓), max boundary (255 chars ✓), 256 chars ✗, wrong type (number)8+ tests
Integrationone representative: missing title → 400 VALIDATION_ERROR (proves Zod is wired)1 test
APIone representative: missing title → 400 (verifies HTTP contract)1 test
E2Enothing — E2E tests do not test field validation0 tests
测试层测试内容测试数量
单元测试缺失、undefined、null、空字符串、最小边界(1个字符 ✓)、最大边界(255个字符 ✓)、256个字符 ✗、类型错误(数字)8+ 个测试
集成测试一个代表性场景:缺失title → 返回400 VALIDATION_ERROR(证明Zod已连通)1个测试
API测试一个代表性场景:缺失title → 返回400(验证HTTP契约)1个测试
E2E测试无 —— E2E测试不测试字段校验0个测试

Testing a
notFound
service branch

测试
notFound
服务分支

LayerWhat to test
Unitmock
prisma.note.findUnique
to return null → verify
Errors.notFound()
thrown; verify downstream mocks NOT called
Integrationrequest with a real non-existent ID in DB → verify 404 response with correct
NOT_FOUND
code
API
GET /api/notes/:nonExistentId
→ verify 404 with correct error body
E2Enothing — E2E tests don't test error branches
测试层测试内容
单元测试mock
prisma.note.findUnique
返回null → 验证抛出
Errors.notFound()
;验证下游mock未被调用
集成测试用数据库中真实不存在的ID发起请求 → 验证返回404响应,携带正确的
NOT_FOUND
错误码
API测试
GET /api/notes/:nonExistentId
→ 验证返回404,携带正确的错误响应体
E2E测试无 —— E2E测试不测试错误分支

Testing an authorization rule

测试鉴权规则

LayerWhat to test
Unitmock
prisma.note.findUnique
to return a note with
organizationId: "other-org"
→ verify
Errors.forbidden()
thrown; verify update mock NOT called
Integrationuser B requests note owned by user A's organization → verify 403 FORBIDDEN response and DB unchanged
APIuser B requests note owned by user A → verify 403 response
E2Everify user B cannot see user A's notes in the UI (data isolation test)

测试层测试内容
单元测试mock
prisma.note.findUnique
返回
organizationId: "other-org"
的笔记 → 验证抛出
Errors.forbidden()
;验证更新mock未被调用
集成测试用户B请求属于用户A组织的笔记 → 验证返回403 FORBIDDEN响应,数据库未变更
API测试用户B请求属于用户A的笔记 → 验证返回403响应
E2E测试验证用户B在UI中看不到用户A的笔记(数据隔离测试)

Completion

完成

After all layers are generated, provide:
File inventory per layer:
LayerFiles createdRun command
Unit
<domain>.schema.test.ts
,
<domain>.service.test.ts
,
schema.helper.ts
,
<domain>.unit-factory.ts
vitest run src/modules/<domain>/test/unit/
Integration
<endpoint>.test.ts
(×N),
<domain>.service.test.ts
,
database.helper.ts
,
auth.helper.ts
,
<domain>.fixture.ts
, api-utils
yarn test:integration
API
<method>-<endpoint>.spec.ts
(×N),
<domain>.factory.ts
,
<domain>.api-utils.ts
,
<domain>.cleanup.ts
npx playwright test --project=api
E2E
<domain>.<feature>.spec.ts
,
<domain>.page.ts
,
<domain>.factory.ts
, setup.ts, cleanup.ts
npx playwright test --project=chromium
所有层生成完成后,提供以下内容:
每层文件清单:
测试层创建的文件运行命令
单元测试
<domain>.schema.test.ts
<domain>.service.test.ts
schema.helper.ts
<domain>.unit-factory.ts
vitest run src/modules/<domain>/test/unit/
集成测试
<endpoint>.test.ts
(×N)、
<domain>.service.test.ts
database.helper.ts
auth.helper.ts
<domain>.fixture.ts
、api-utils
yarn test:integration
API测试
<method>-<endpoint>.spec.ts
(×N)、
<domain>.factory.ts
<domain>.api-utils.ts
<domain>.cleanup.ts
npx playwright test --project=api
E2E测试
<domain>.<feature>.spec.ts
<domain>.page.ts
<domain>.factory.ts
、setup.ts、cleanup.ts
npx playwright test --project=chromium