mcpField
T
typescript-unit-testing

typescript-unit-testing

github.com/bmad-labsテスト・品質19501 回インストール6 日前に更新
リポジトリ

typescript-unit-testing について

TypeScriptプロジェクト向けのユニットテストスキルです。セットアップ、作成、レビュー、実行、デバッグ、最適化の作業別ワークフローを選び、依存関係の分離や境界・エラーケースの確認を支援します。

主な機能

  1. 01作業に応じたテストワークフロー選択
  2. 02NestJSテストのリファレンス
  3. 03データベースとメッセージングのテスト
  4. 04AAAとモックのルール
  5. 05失敗テストを個別に調査
  6. 06性能とカバレッジの要件

活用シーン

  1. 01新規プロジェクトのテスト基盤設定
  2. 02サービスやコントローラーの単体テスト作成
  3. 03テスト品質のレビューと境界ケースの補完
  4. 04失敗テストや遅いテストの原因調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/bmad-labs/skills --skill typescript-unit-testing

インストール後、Claude Code で/typescript-unit-testingを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

LICENSE
references/common/
assertions.md
detect-open-handles.md
examples.md
knowledge.md
performance-optimization.md
rules.md
references/kafka/
kafka.md
references/mocking/
deep-mocked.md
factories.md
jest-native.md
references/nestjs/
controllers.md
guards.md
interceptors.md
pipes-filters.md
services.md
references/redis/
redis.md
references/repository/
mongodb.md
postgres.md
workflows/debugging/
workflow.md
workflows/debugging/steps/
step-01-init.md
step-01b-continue.md
step-02-classify-failure.md
step-03-analyze.md
step-04-implement-fix.md
step-05-verify-fix.md
step-06-document-resolution.md
workflows/debugging/templates/
output-template.md
workflows/optimizing/steps/
step-01-init.md
step-01b-continue.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
ワークフロー実行プロトコル
  1. 必ず最初にワークフローファイルを読み込む — 作業に着手する前に、ワークフロー全体を読んでください
  2. 各手順を順番に実行する — 次に進む前に、チェックポイントを完了してください
  3. 指示に従ってナレッジファイルを読み込む — 各ワークフローで、読み込む references/ ファイルが指定されています
  4. 完了後に準拠状況を確認する — 品質を確保するため、関連する参照ファイルを再度読み込んでください

ナレッジベースの構成

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

タスク別クイックリファレンス

ユニットテストを作成する
  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
モックをセットアップする
  1. references/mocking/deep-mocked.md を読む — DeepMocked のパターン
  2. references/mocking/jest-native.md を読む — Jest 標準のパターン
  3. references/mocking/factories.md を読む — テストデータファクトリー
リポジトリーをテストする
  1. MongoDB:references/repository/mongodb.md
  2. PostgreSQL:references/repository/postgres.md
Kafka をテストする(NestJS マイクロサービス)
  • references/kafka/kafka.md を読む — ClientKafka のモック、@MessagePattern/@EventPattern ハンドラー、emit/send のテスト
Redis をテストする
  • references/redis/redis.md を読む — キャッシュ操作、ヘルスチェック、適切な縮退動作
例
  • 包括的なパターンについては references/common/examples.md を読む
テストのパフォーマンスを最適化する
  1. references/common/performance-optimization.md を読む — ワーカー設定、キャッシュ、CI の最適化
  2. references/common/detect-open-handles.md を読む — 正常終了を妨げるオープンハンドルの修正
オープンハンドルをデバッグする
  • references/common/detect-open-handles.md を読む — 検出コマンド、一般的なハンドルの種類、クリーンアップのパターン

基本原則

0. コンテキスト効率(テスト出力を一時ファイルに保存)

ユニットテストの出力は、必ずコンソールではなく一時ファイルにリダイレクトしてください。テスト出力は冗長になりやすく、エージェントのコンテキストを圧迫します。

重要:複数のエージェントを実行したときに競合しないよう、ファイル名には一意のセッション ID を使用してください。

# 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

一時ファイル(エージェントごとに一意な ${UT_SESSION} を使用):

  • /tmp/ut-${UT_SESSION}-output.log - テスト出力全体
  • /tmp/ut-${UT_SESSION}-failures.md - 1件ずつ修正するための追跡ファイル
  • /tmp/ut-${UT_SESSION}-debug.log - デバッグ実行
  • /tmp/ut-${UT_SESSION}-verify.log - 検証実行
  • /tmp/ut-${UT_SESSION}-coverage.log - カバレッジ出力
1. AAA パターン(必須)

すべてのユニットテストは、必ず Arrange-Act-Assert に従ってください:

it('should return user when found', async () => {
  // Arrange
  const userId = 'user-123';
  mockRepository.findById.mockResolvedValue({
    id: userId,
    email: '[email protected]',
    name: 'Test User',
  });

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

  // Assert
  expect(result).toEqual({
    id: userId,
    email: '[email protected]',
    name: 'Test User',
  });
  expect(mockRepository.findById).toHaveBeenCalledWith(userId);
});
2. SUT には target を使用

テスト対象のシステムには、常に target という名前を使用してください:

let target: UserService;
let mockRepository: DeepMocked<UserRepository>;
3. DeepMocked パターン

型安全なモックには @golevelup/ts-jest を使用してください:

import { createMock, DeepMocked } from '@golevelup/ts-jest';

let mockService: DeepMocked<UserService>;

beforeEach(() => {
  mockService = createMock<UserService>();
});
4. 具体的なアサーション

存在することだけでなく、正確な値をアサートしてください:

// WRONG
expect(result).toBeDefined();
expect(result.id).toBeDefined();

// CORRECT
expect(result).toEqual({
  id: 'user-123',
  email: '[email protected]',
  name: 'Test User',
});
5. すべての依存関係をモック

外部サービスをモックし、ユニットテストでは実際のデータベースを使用しないでください:

// Unit Test: Mock repository
{ provide: UserRepository, useValue: mockRepository }

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

標準テストテンプレート

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: '[email protected]',
      });

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

      // Assert
      expect(result).toEqual({ id: 'user-123', email: '[email protected]' });
    });

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

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

テストカバレッジの要件

カテゴリ優先度説明
正常系必須有効な入力に対して期待される出力が得られる
エッジケース必須空の配列、null 値、境界値
エラーケース必須見つからない場合、検証の失敗
例外動作必須正しい型、エラーコード、メッセージ
ビジネスルール必須ドメインロジック、計算
入力検証必須無効な入力、型の不一致

カバレッジ目標: 新規コードで 80% 以上


失敗解決プロトコル

最重要:テストは1件ずつ修正してください。修正中にテストスイート全体を繰り返し実行しないでください。

ユニットテストが失敗した場合:

  1. セッションを初期化(開始時に1回):
    export UT_SESSION=$(date +%s)-$$
    
  2. 追跡ファイルを作成:失敗したテストをすべて /tmp/ut-${UT_SESSION}-failures.md に記録します
  3. 失敗したテストを1件選択し、そのテストだけに取り組みます
  4. そのテストだけを実行します(テストスイート全体は実行しないでください):
    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回実行します:
    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. 追跡ファイルで FIXED と記録します
  8. 次の失敗したテストに進み、手順3~7を繰り返します
  9. すべての個別テストが通過した後に限り、テストスイート全体を1回だけ実行します
  10. クリーンアップ:rm -f /tmp/ut-${UT_SESSION}-*.log /tmp/ut-${UT_SESSION}-*.md

理由:テストスイート全体の実行は、時間とコンテキストを浪費します。失敗したテストごとに出力が増え、デバッグが難しくなります。


命名規則

テストファイル
  • パターン:*.spec.ts
  • 場所:ソースファイルと同じディレクトリ
テスト構造
describe('ClassName', () => {
  describe('methodName', () => {
    it('should [expected behavior] when [condition]', () => {});
  });
});
変数名
変数規則
SUTtarget
モックmock を接頭辞として付ける(mockRepository、mockService)
モック型DeepMocked<T>

ユニットテストの対象外

次の項目に対して、ユニットテストを作成しないでください:

  • インターフェース - 型定義のみで、実行時の動作がありません
  • 列挙型 - 静的な値のマッピングで、テストするロジックがありません
  • 定数 - 静的な値で、動作がありません
  • 型エイリアス - 型定義のみです
  • 単純な DTO - ロジックを含まないデータ構造です

実行可能なロジックを含むファイル(メソッドを持つクラス、動作を持つ関数)のみをテストしてください。


避けるべきアンチパターン

しないこと理由代わりにすること
存在することだけをアサートする値が間違っていても検出できません具体的な値をアサートする
条件付きアサーション非決定的になりますテストケースを分ける
プライベートメソッドをテストする実装に密結合しますパブリックインターフェース経由でテストする
テスト間で状態を共有する不安定なテストの原因になりますbeforeEach で毎回新しくセットアップする
サービス内でリポジトリをモックする実装をテストすることになりますインターフェースをモックする
モックの検証を省略する動作を検証できませんモックの呼び出しを検証する
インターフェース、列挙型、定数をテストするテストする動作がありませんこれらのファイルはスキップする

チェックリスト

セットアップ:

  • テスト対象のシステムには target を使用する
  • すべてのモックに mock プレフィックスを使用する
  • DeepMocked<T> 型を使用する
  • .setLogger(new MockLoggerService()) を含める
  • コメント付きの AAA パターンに従う
  • afterEach でモックをリセットする

カバレッジ:

  • すべてのパブリックメソッドについて正常系のテストを行う
  • エッジケース(空、null、境界値)のテストを行う
  • エラーケース(見つからない場合、検証の失敗)のテストを行う
  • 例外の型とエラーコードを検証する
  • モックの呼び出し(パラメーターと回数)を検証する

品質:

  • 新しいコードのカバレッジを80%以上にする
  • ログ呼び出しに対するアサーションを行わない
  • テスト間に依存関係を持たせない
  • いずれかのフィールドが異なる場合にテストが失敗する

コメント