typescript-unit-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Unit Testing Skill

单元测试技能

Unit testing validates individual functions, methods, and classes in isolation by mocking all external dependencies.

单元测试通过模拟所有外部依赖,独立验证单个函数、方法和类的功能。

Workflows

工作流

For guided, step-by-step execution of unit testing tasks, use the appropriate workflow:
WorkflowPurposeWhen to Use
SetupInitialize test infrastructureNew project or missing test setup
WritingWrite new unit testsCreating tests for components
ReviewingReview existing testsCode review, quality audit
RunningExecute testsRunning tests, analyzing results
DebuggingFix failing testsTests failing, need diagnosis
OptimizingImprove test performanceSlow tests, maintainability
如需按步骤执行单元测试任务,请使用对应的工作流:
工作流用途适用场景
配置初始化测试基础设施新项目或缺少测试配置的项目
编写编写新单元测试为组件创建测试
评审评审现有测试代码评审、质量审计
运行执行测试运行测试、分析结果
调试修复失败测试测试失败、需要诊断问题
优化提升测试性能测试缓慢、需要提升可维护性

Workflow Selection Guide

工作流选择指南

IMPORTANT: Before starting any testing task, identify the user's intent and load the appropriate workflow.
重要提示:在开始任何测试任务前,请先明确用户意图,再加载对应的工作流。

Detect User Intent → Select Workflow

识别用户意图 → 选择工作流

User Says / WantsWorkflow to LoadFile
"Set up tests", "configure Jest", "add testing to project", "install test dependencies"Setup
workflows/setup/workflow.md
"Write tests", "add tests", "create tests", "test this service/controller"Writing
workflows/writing/workflow.md
"Review tests", "check test quality", "audit tests", "are these tests good?"Reviewing
workflows/reviewing/workflow.md
"Run tests", "execute tests", "check if tests pass", "show test results"Running
workflows/running/workflow.md
"Fix tests", "debug tests", "tests are failing", "why is this test broken?"Debugging
workflows/debugging/workflow.md
"Speed up tests", "optimize tests", "tests are slow", "fix open handles"Optimizing
workflows/optimizing/workflow.md
用户需求应加载的工作流文件
"配置测试"、"配置Jest"、"为项目添加测试"、"安装测试依赖"配置
workflows/setup/workflow.md
"编写测试"、"添加测试"、"创建测试"、"测试这个服务/控制器"编写
workflows/writing/workflow.md
"评审测试"、"检查测试质量"、"审计测试"、"这些测试合格吗?"评审
workflows/reviewing/workflow.md
"运行测试"、"执行测试"、"检查测试是否通过"、"展示测试结果"运行
workflows/running/workflow.md
"修复测试"、"调试测试"、"测试失败了"、"这个测试为什么坏了?"调试
workflows/debugging/workflow.md
"加速测试"、"优化测试"、"测试太慢了"、"修复未关闭句柄"优化
workflows/optimizing/workflow.md

Workflow Execution Protocol

工作流执行规范

  1. ALWAYS load the workflow file first - Read the full workflow before taking action
  2. Follow each step in order - Complete checkpoints before proceeding
  3. Load knowledge files as directed - Each workflow specifies which
    references/
    files to read
  4. Verify compliance after completion - Re-read relevant reference files to ensure quality

  1. 必须先加载工作流文件 - 在采取行动前,先完整阅读工作流内容
  2. 按顺序执行每一步 - 完成检查点后再继续下一步
  3. 按要求加载知识库文件 - 每个工作流会指定需要读取的
    references/
    下的文件
  4. 完成后验证合规性 - 重新阅读相关参考文件,确保质量达标

Knowledge Base Structure

知识库结构

references/
├── common/              # Core testing fundamentals
│   ├── knowledge.md     # Testing philosophy and test pyramid
│   ├── rules.md         # Mandatory testing rules (AAA, naming, coverage)
│   ├── assertions.md    # Assertion patterns and matchers
│   ├── examples.md      # Comprehensive examples by category
│   ├── detect-open-handles.md   # Open handle detection and cleanup
│   └── performance-optimization.md  # Jest runtime optimization
├── nestjs/              # NestJS component testing
│   ├── services.md      # Service/usecase testing patterns
│   ├── controllers.md   # Controller testing patterns
│   ├── guards.md        # Guard testing patterns
│   ├── interceptors.md  # Interceptor testing patterns
│   └── pipes-filters.md # Pipe and filter testing
├── mocking/             # Mock patterns and strategies
│   ├── deep-mocked.md   # @golevelup/ts-jest patterns
│   ├── jest-native.md   # Jest.fn, spyOn, mock patterns
│   └── factories.md     # Test data factory patterns
├── repository/          # Repository testing
│   ├── mongodb.md       # mongodb-memory-server patterns
│   └── postgres.md      # pg-mem patterns
├── kafka/               # NestJS Kafka microservices testing
│   └── kafka.md         # ClientKafka, @MessagePattern, @EventPattern handlers
└── redis/               # Redis cache testing
    └── redis.md         # Cache operations, health checks, graceful degradation
references/
├── common/              # 核心测试基础
│   ├── knowledge.md     # 测试理念与测试金字塔
│   ├── rules.md         # 强制测试规则(AAA、命名、覆盖率)
│   ├── assertions.md    # 断言模式与匹配器
│   ├── examples.md      # 按类别划分的综合示例
│   ├── detect-open-handles.md   # 未关闭句柄的检测与清理
│   └── performance-optimization.md  # Jest运行时优化
├── nestjs/              # NestJS组件测试
│   ├── services.md      # 服务/用例测试模式
│   ├── controllers.md   # 控制器测试模式
│   ├── guards.md        # 守卫测试模式
│   ├── interceptors.md  # 拦截器测试模式
│   └── pipes-filters.md # 管道与过滤器测试
├── mocking/             # 模拟模式与策略
│   ├── deep-mocked.md   # @golevelup/ts-jest模式
│   ├── jest-native.md   # Jest.fn、spyOn、模拟模式
│   └── factories.md     # 测试数据工厂模式
├── repository/          # 仓库测试
│   ├── mongodb.md       # mongodb-memory-server模式
│   └── postgres.md      # pg-mem模式
├── kafka/               # NestJS Kafka微服务测试
│   └── kafka.md         # ClientKafka、@MessagePattern、@EventPattern处理器
└── redis/               # Redis缓存测试
    └── redis.md         # 缓存操作、健康检查、优雅降级

Quick Reference by Task

按任务分类的快速参考

Write Unit Tests

编写单元测试

  1. MANDATORY: Read
    references/common/rules.md
    - AAA pattern, naming, coverage
  2. Read
    references/common/assertions.md
    - Assertion best practices
  3. Read component-specific files:
    • Services:
      references/nestjs/services.md
    • Controllers:
      references/nestjs/controllers.md
    • Guards:
      references/nestjs/guards.md
    • Interceptors:
      references/nestjs/interceptors.md
    • Pipes/Filters:
      references/nestjs/pipes-filters.md
  1. 强制要求:阅读
    references/common/rules.md
    - AAA模式、命名规范、覆盖率要求
  2. 阅读
    references/common/assertions.md
    - 断言最佳实践
  3. 阅读对应组件的文件:
    • 服务
      references/nestjs/services.md
    • 控制器
      references/nestjs/controllers.md
    • 守卫
      references/nestjs/guards.md
    • 拦截器
      references/nestjs/interceptors.md
    • 管道/过滤器
      references/nestjs/pipes-filters.md

Setup Mocking

配置模拟

  1. Read
    references/mocking/deep-mocked.md
    - DeepMocked patterns
  2. Read
    references/mocking/jest-native.md
    - Native Jest patterns
  3. Read
    references/mocking/factories.md
    - Test data factories
  1. 阅读
    references/mocking/deep-mocked.md
    - DeepMocked模式
  2. 阅读
    references/mocking/jest-native.md
    - Jest原生模拟模式
  3. 阅读
    references/mocking/factories.md
    - 测试数据工厂

Test Repositories

测试仓库

  1. MongoDB:
    references/repository/mongodb.md
  2. PostgreSQL:
    references/repository/postgres.md
  1. MongoDB
    references/repository/mongodb.md
  2. PostgreSQL
    references/repository/postgres.md

Test Kafka (NestJS Microservices)

测试Kafka(NestJS微服务)

  • Read
    references/kafka/kafka.md
    - ClientKafka mocking, @MessagePattern/@EventPattern handlers, emit/send testing
  • 阅读
    references/kafka/kafka.md
    - ClientKafka模拟、@MessagePattern/@EventPattern处理器、emit/send测试

Test Redis

测试Redis

  • Read
    references/redis/redis.md
    - Cache operations, health checks, graceful degradation
  • 阅读
    references/redis/redis.md
    - 缓存操作、健康检查、优雅降级

Examples

示例

  • Read
    references/common/examples.md
    for comprehensive patterns
  • 阅读
    references/common/examples.md
    获取综合模式示例

Optimize Test Performance

优化测试性能

  1. Read
    references/common/performance-optimization.md
    - Worker config, caching, CI optimization
  2. Read
    references/common/detect-open-handles.md
    - Fix open handles preventing clean exit
  1. 阅读
    references/common/performance-optimization.md
    - 工作线程配置、缓存、CI优化
  2. 阅读
    references/common/detect-open-handles.md
    - 修复阻止程序正常退出的未关闭句柄

Debug Open Handles

调试未关闭句柄

  • Read
    references/common/detect-open-handles.md
    - Detection commands, common handle types, cleanup patterns

  • 阅读
    references/common/detect-open-handles.md
    - 检测命令、常见句柄类型、清理模式

Core Principles

核心原则

0. Context Efficiency (Temp File Output)

0. 上下文效率(临时文件输出)

ALWAYS redirect unit test output to temp files, NOT console. Test output can be verbose and bloats agent context.
IMPORTANT: Use unique session ID in filenames to prevent conflicts when multiple agents run.
bash
undefined
必须将单元测试输出重定向到临时文件,而非控制台。测试输出可能非常冗长,会占用过多Agent上下文。
重要提示:在文件名中使用唯一会话ID,避免多个Agent运行时发生冲突。
bash
undefined

Initialize session (once at start of testing session)

初始化会话(测试会话开始时执行一次)

export UT_SESSION=$(date +%s)-$$
export UT_SESSION=$(date +%s)-$$

Standard pattern - redirect output to temp file (NO console output)

标准模式 - 将输出重定向到临时文件(不要输出到控制台)

npm test > /tmp/ut-${UT_SESSION}-output.log 2>&1
npm test > /tmp/ut-${UT_SESSION}-output.log 2>&1

Read summary only (last 50 lines)

仅读取摘要(最后50行)

tail -50 /tmp/ut-${UT_SESSION}-output.log
tail -50 /tmp/ut-${UT_SESSION}-output.log

Get failure details

获取失败详情

grep -B 2 -A 15 "FAIL|✕" /tmp/ut-${UT_SESSION}-output.log
grep -B 2 -A 15 "FAIL|✕" /tmp/ut-${UT_SESSION}-output.log

Cleanup when done

完成后清理

rm -f /tmp/ut-${UT_SESSION}-.log /tmp/ut-${UT_SESSION}-.md

**Temp Files** (with `${UT_SESSION}` unique per agent):
- `/tmp/ut-${UT_SESSION}-output.log` - Full test output
- `/tmp/ut-${UT_SESSION}-failures.md` - Tracking file for one-by-one fixing
- `/tmp/ut-${UT_SESSION}-debug.log` - Debug runs
- `/tmp/ut-${UT_SESSION}-verify.log` - Verification runs
- `/tmp/ut-${UT_SESSION}-coverage.log` - Coverage output
rm -f /tmp/ut-${UT_SESSION}-.log /tmp/ut-${UT_SESSION}-.md

**临时文件**(每个Agent的`${UT_SESSION}`唯一):
- `/tmp/ut-${UT_SESSION}-output.log` - 完整测试输出
- `/tmp/ut-${UT_SESSION}-failures.md` - 逐个修复的跟踪文件
- `/tmp/ut-${UT_SESSION}-debug.log` - 调试运行日志
- `/tmp/ut-${UT_SESSION}-verify.log` - 验证运行日志
- `/tmp/ut-${UT_SESSION}-coverage.log` - 覆盖率输出

1. AAA Pattern (Mandatory)

1. AAA模式(强制要求)

ALL unit tests MUST follow Arrange-Act-Assert:
typescript
it('should return user when found', async () => {
  // Arrange
  const userId = 'user-123';
  mockRepository.findById.mockResolvedValue({
    id: userId,
    email: 'test@example.com',
    name: 'Test User',
  });

  // Act
  const result = await target.getUser(userId);

  // Assert
  expect(result).toEqual({
    id: userId,
    email: 'test@example.com',
    name: 'Test User',
  });
  expect(mockRepository.findById).toHaveBeenCalledWith(userId);
});
所有单元测试必须遵循Arrange-Act-Assert(准备-执行-断言)模式:
typescript
it('should return user when found', async () => {
  // Arrange(准备)
  const userId = 'user-123';
  mockRepository.findById.mockResolvedValue({
    id: userId,
    email: 'test@example.com',
    name: 'Test User',
  });

  // Act(执行)
  const result = await target.getUser(userId);

  // Assert(断言)
  expect(result).toEqual({
    id: userId,
    email: 'test@example.com',
    name: 'Test User',
  });
  expect(mockRepository.findById).toHaveBeenCalledWith(userId);
});

2. Use
target
for SUT

2. 使用
target
指代被测系统(SUT)

Always name the system under test as
target
:
typescript
let target: UserService;
let mockRepository: DeepMocked<UserRepository>;
始终将被测系统命名为
target
typescript
let target: UserService;
let mockRepository: DeepMocked<UserRepository>;

3. DeepMocked Pattern

3. DeepMocked模式

Use
@golevelup/ts-jest
for type-safe mocks:
typescript
import { createMock, DeepMocked } from '@golevelup/ts-jest';

let mockService: DeepMocked<UserService>;

beforeEach(() => {
  mockService = createMock<UserService>();
});
使用
@golevelup/ts-jest
实现类型安全的模拟:
typescript
import { createMock, DeepMocked } from '@golevelup/ts-jest';

let mockService: DeepMocked<UserService>;

beforeEach(() => {
  mockService = createMock<UserService>();
});

4. Specific Assertions

4. 具体断言

Assert exact values, not just existence:
typescript
// WRONG
expect(result).toBeDefined();
expect(result.id).toBeDefined();

// CORRECT
expect(result).toEqual({
  id: 'user-123',
  email: 'test@example.com',
  name: 'Test User',
});
断言精确值,而非仅断言存在性:
typescript
// 错误示例
expect(result).toBeDefined();
expect(result.id).toBeDefined();

// 正确示例
expect(result).toEqual({
  id: 'user-123',
  email: 'test@example.com',
  name: 'Test User',
});

5. Mock All Dependencies

5. 模拟所有依赖

Mock external services, never real databases for unit tests:
typescript
// Unit Test: Mock repository
{ provide: UserRepository, useValue: mockRepository }

// Repository Test: Use in-memory database
const mongoServer = await createMongoMemoryServer();

模拟外部服务,单元测试中绝不使用真实数据库:
typescript
// 单元测试:模拟仓库
{ provide: UserRepository, useValue: mockRepository }

// 仓库测试:使用内存数据库
const mongoServer = await createMongoMemoryServer();

Standard Test Template

标准测试模板

typescript
import { Test, TestingModule } from '@nestjs/testing';
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { MockLoggerService } from 'src/shared/logger/services/mock-logger.service';

describe('UserService', () => {
  let target: UserService;
  let mockRepository: DeepMocked<UserRepository>;

  beforeEach(async () => {
    // Arrange: Create mocks
    mockRepository = createMock<UserRepository>();

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UserService,
        { provide: UserRepository, useValue: mockRepository },
      ],
    })
      .setLogger(new MockLoggerService())
      .compile();

    target = module.get<UserService>(UserService);
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  describe('getUser', () => {
    it('should return user when found', async () => {
      // Arrange
      mockRepository.findById.mockResolvedValue({
        id: 'user-123',
        email: 'test@example.com',
      });

      // Act
      const result = await target.getUser('user-123');

      // Assert
      expect(result).toEqual({ id: 'user-123', email: 'test@example.com' });
    });

    it('should throw NotFoundException when user not found', async () => {
      // Arrange
      mockRepository.findById.mockResolvedValue(null);

      // Act & Assert
      await expect(target.getUser('invalid')).rejects.toThrow(NotFoundException);
    });
  });
});

typescript
import { Test, TestingModule } from '@nestjs/testing';
import { createMock, DeepMocked } from '@golevelup/ts-jest';
import { MockLoggerService } from 'src/shared/logger/services/mock-logger.service';

describe('UserService', () => {
  let target: UserService;
  let mockRepository: DeepMocked<UserRepository>;

  beforeEach(async () => {
    // 准备:创建模拟
    mockRepository = createMock<UserRepository>();

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        UserService,
        { provide: UserRepository, useValue: mockRepository },
      ],
    })
      .setLogger(new MockLoggerService())
      .compile();

    target = module.get<UserService>(UserService);
  });

  afterEach(() => {
    jest.clearAllMocks();
  });

  describe('getUser', () => {
    it('should return user when found', async () => {
      // 准备
      mockRepository.findById.mockResolvedValue({
        id: 'user-123',
        email: 'test@example.com',
      });

      // 执行
      const result = await target.getUser('user-123');

      // 断言
      expect(result).toEqual({ id: 'user-123', email: 'test@example.com' });
    });

    it('should throw NotFoundException when user not found', async () => {
      // 准备
      mockRepository.findById.mockResolvedValue(null);

      // 执行 & 断言
      await expect(target.getUser('invalid')).rejects.toThrow(NotFoundException);
    });
  });
});

Test Coverage Requirements

测试覆盖率要求

CategoryPriorityDescription
Happy pathMANDATORYValid inputs producing expected outputs
Edge casesMANDATORYEmpty arrays, null values, boundaries
Error casesMANDATORYNot found, validation failures
Exception behaviorMANDATORYCorrect type, error code, message
Business rulesMANDATORYDomain logic, calculations
Input validationMANDATORYInvalid inputs, type mismatches
Coverage Target: 80%+ for new code

类别优先级描述
正常流程强制要求有效输入产生预期输出
边缘场景强制要求空数组、null值、边界值
错误场景强制要求未找到、验证失败
异常行为强制要求正确的异常类型、错误码、消息
业务规则强制要求领域逻辑、计算逻辑
输入验证强制要求无效输入、类型不匹配
覆盖率目标: 新代码覆盖率≥80%

Failure Resolution Protocol

失败修复流程

CRITICAL: Fix ONE test at a time. NEVER run full suite repeatedly while fixing.
When unit tests fail:
  1. Initialize session (once at start):
    bash
    export UT_SESSION=$(date +%s)-$$
  2. Create tracking file:
    /tmp/ut-${UT_SESSION}-failures.md
    with all failing tests
  3. Select ONE failing test - work on only this test
  4. Run ONLY that test (never full suite):
    bash
    npm test -- -t "test name" > /tmp/ut-${UT_SESSION}-debug.log 2>&1
    tail -50 /tmp/ut-${UT_SESSION}-debug.log
  5. Fix the issue - analyze error, make targeted fix
  6. Verify fix - run same test 3-5 times:
    bash
    for i in {1..5}; do npm test -- -t "test name" > /tmp/ut-${UT_SESSION}-run$i.log 2>&1 && echo "Run $i: PASS" || echo "Run $i: FAIL"; done
  7. Mark as FIXED in tracking file
  8. Move to next failing test - repeat steps 3-7
  9. Run full suite ONLY ONCE after ALL individual tests pass
  10. Cleanup:
    rm -f /tmp/ut-${UT_SESSION}-*.log /tmp/ut-${UT_SESSION}-*.md
WHY: Running full suite wastes time and context. Each failing test pollutes output, making debugging harder.

关键提示:一次只修复一个测试。修复过程中绝不要反复运行完整测试套件。
当单元测试失败时:
  1. 初始化会话(开始时执行一次):
    bash
    export UT_SESSION=$(date +%s)-$$
  2. 创建跟踪文件
    /tmp/ut-${UT_SESSION}-failures.md
    ,记录所有失败的测试
  3. 选择一个失败测试 - 仅处理该测试
  4. 仅运行该测试(绝不运行完整套件):
    bash
    npm test -- -t "test name" > /tmp/ut-${UT_SESSION}-debug.log 2>&1
    tail -50 /tmp/ut-${UT_SESSION}-debug.log
  5. 修复问题 - 分析错误,进行针对性修复
  6. 验证修复 - 重复运行该测试3-5次:
    bash
    for i in {1..5}; do npm test -- -t "test name" > /tmp/ut-${UT_SESSION}-run$i.log 2>&1 && echo "Run $i: PASS" || echo "Run $i: FAIL"; done
  7. 在跟踪文件中标记为已修复
  8. 处理下一个失败测试 - 重复步骤3-7
  9. 所有单个测试通过后,仅运行一次完整套件
  10. 清理
    rm -f /tmp/ut-${UT_SESSION}-*.log /tmp/ut-${UT_SESSION}-*.md
原因:运行完整套件会浪费时间和上下文,每个失败测试的输出会干扰调试,增加问题定位难度。

Naming Conventions

命名规范

Test Files

测试文件

  • Pattern:
    *.spec.ts
  • Location: Co-located with source file
  • 命名模式:
    *.spec.ts
  • 位置:与源文件同目录

Test Structure

测试结构

typescript
describe('ClassName', () => {
  describe('methodName', () => {
    it('should [expected behavior] when [condition]', () => {});
  });
});
typescript
describe('ClassName', () => {
  describe('methodName', () => {
    it('should [预期行为] when [条件]', () => {});
  });
});

Variable Names

变量命名

VariableConvention
SUT
target
Mocks
mock
prefix (
mockRepository
,
mockService
)
Mock Type
DeepMocked<T>

变量规范
被测系统(SUT)
target
模拟对象前缀为
mock
(如
mockRepository
mockService
模拟类型
DeepMocked<T>

What NOT to Unit Test

无需进行单元测试的内容

Do NOT create unit tests for:
  • Interfaces - Type definitions only, no runtime behavior
  • Enums - Static value mappings, no logic to test
  • Constants - Static values, no behavior
  • Type aliases - Type definitions only
  • Plain DTOs - Data structures without logic
Only test files containing executable logic (classes with methods, functions with behavior).

请勿为以下内容创建单元测试:
  • 接口 - 仅为类型定义,无运行时行为
  • 枚举 - 静态值映射,无逻辑需测试
  • 常量 - 静态值,无行为
  • 类型别名 - 仅为类型定义
  • 普通DTO - 无逻辑的数据结构
仅为包含可执行逻辑的文件编写测试(含方法的类、有行为的函数)。

Anti-Patterns to Avoid

需避免的反模式

Don'tWhyDo Instead
Assert only existenceDoesn't catch wrong valuesAssert specific values
Conditional assertionsNon-deterministicSeparate test cases
Test private methodsCouples to implementationTest via public interface
Share state between testsCauses flaky testsFresh setup in beforeEach
Mock repositories in servicesTests implementationMock interfaces
Skip mock verificationDoesn't validate behaviorVerify mock calls
Test interfaces/enums/constantsNo behavior to testSkip these files

不要做原因正确做法
仅断言存在性无法捕获值错误断言具体值
条件断言测试结果不确定拆分测试用例
测试私有方法与实现细节耦合通过公共接口测试
测试间共享状态导致测试不稳定在beforeEach中重新初始化
在服务测试中模拟仓库测试实现细节模拟接口
跳过模拟调用验证无法验证行为正确性验证模拟调用
测试接口/枚举/常量无行为需测试跳过这些文件

Checklist

检查清单

Setup:
  • Use
    target
    for system under test
  • Use
    mock
    prefix for all mocks
  • Use
    DeepMocked<T>
    type
  • Include
    .setLogger(new MockLoggerService())
  • Follow AAA pattern with comments
  • Reset mocks in
    afterEach
Coverage:
  • Happy path tests for all public methods
  • Edge case tests (empty, null, boundaries)
  • Error case tests (not found, validation failures)
  • Exception type and error code verification
  • Mock call verification (parameters + count)
Quality:
  • 80%+ coverage on new code
  • No assertions on log calls
  • No test interdependence
  • Tests fail when any field differs
配置:
  • 使用
    target
    指代被测系统
  • 所有模拟对象使用
    mock
    前缀
  • 使用
    DeepMocked<T>
    类型
  • 包含
    .setLogger(new MockLoggerService())
  • 带注释遵循AAA模式
  • afterEach
    中重置模拟
覆盖率:
  • 所有公共方法的正常流程测试
  • 边缘场景测试(空值、边界值等)
  • 错误场景测试(未找到、验证失败等)
  • 异常类型和错误码验证
  • 模拟调用验证(参数+调用次数)
质量:
  • 新代码覆盖率≥80%
  • 不对日志调用进行断言
  • 测试间无依赖
  • 任何字段不一致时测试都会失败