Skip to main content

typescript-unit-testing

Unit testing for TypeScript/NestJS projects using Jest, @golevelup/ts-jest (DeepMocked/createMock), and in-memory databases, with AAA structure. Use whenever the user is working on `.spec.ts` files or asks to set up Jest, write/add tests for a service/usecase/controller/guard/interceptor/pipe/filter, mock dependencies, review test quality or coverage, run unit tests, debug failing or flaky tests, or optimize test performance and open handles.

跳到安装

来源信息

仓库
bmad-labs/skills
最近来源活动
2026年5月7日 03:47
检测到的 SKILL.md 语言
英语
星标
15
分支
4

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
81 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
typescript-unit-testing
description
Unit testing for TypeScript/NestJS projects using Jest, @golevelup/ts-jest (DeepMocked/createMock), and in-memory databases, with AAA structure. Use whenever the user is working on `.spec.ts` files or asks to set up Jest, write/add tests for a service/usecase/controller/guard/interceptor/pipe/filter, mock dependencies, review test quality or coverage, run unit tests, debug failing or flaky tests, or optimize test performance and open handles.
# 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: | Workflow | Purpose | When to Use | |----------|---------|-------------| | [Setup](workflows/setup/workflow.md) | Initialize test infrastructure | New project or missing test setup | | [Writing](workflows/writing/workflow.md) | Write new unit tests | Creating tests for components | | [Reviewing](workflows/reviewing/workflow.md) | Review existing tests | Code review, quality audit | | [Running](workflows/running/workflow.md) | Execute tests | Running tests, analyzing results | | [Debugging](workflows/debugging/workflow.md) | Fix failing tests | Tests failing, need diagnosis | | [Optimizing](workflows/optimizing/workflow.md) | Improve test performance | Slow 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 / Wants | Workflow to Load | File | |-------------------|------------------|------| | "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` | ### 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 --- ## 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 ``` ## 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` ### 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 ### Test Repositories 1. **MongoDB**: `references/repository/mongodb.md` 2. **PostgreSQL**: `references/repository/postgres.md` ### Test Kafka (NestJS Microservices) - Read `references/kafka/kafka.md` - ClientKafka mocking, @MessagePattern/@EventPattern handlers, emit/send testing ### Test Redis - Read `references/redis/redis.md` - Cache operations, health checks, graceful degradation ### Examples - Read `references/common/examples.md` for comprehensive patterns ### 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 ### Debug Open Handles - Read `references/common/detect-open-handles.md` - Detection commands, common handle types, cleanup patterns --- ## Core Principles ### 0. Context Efficiency (Temp File Output) **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 # Initialize session (once at start of testing session) 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 # Read summary only (last 50 lines) tail -50 /tmp/ut-${UT_SESSION}-output.log # Get failure details 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 ### 1. AAA Pattern (Mandatory) 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); }); ``` ### 2. Use `target` for SUT Always name the system under test as `target`: ```typescript let target: UserService; let mockRepository: DeepMocked<UserRepository>; ``` ### 3. DeepMocked Pattern Use `@golevelup/ts-jest` for type-safe mocks: ```typescript import { createMock, DeepMocked } from '@golevelup/ts-jest'; let mockService: DeepMocked<UserService>; beforeEach(() => { mockService = createMock<UserService>(); }); ``` ### 4. Specific Assertions 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', }); ``` ### 5. Mock All Dependencies 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(); ``` --- ## 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); }); }); }); ``` --- ## Test Coverage Requirements | Category | Priority | Description | |----------|----------|-------------| | Happy path | MANDATORY | Valid inputs producing expected outputs | | Edge cases | MANDATORY | Empty arrays, null values, boundaries | | Error cases | MANDATORY | Not found, validation failures | | Exception behavior | MANDATORY | Correct type, error code, message | | Business rules | MANDATORY | Domain logic, calculations | | Input validation | MANDATORY | Invalid inputs, type mismatches | **Coverage Target:** 80%+ for new code --- ## 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. --- ## Naming Conventions ### Test Files - Pattern: `*.spec.ts` - Location: Co-located with source file ### Test Structure ```typescript describe('ClassName', () => { describe('methodName', () => {
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看