Dev Study
NestJS コース

34. ユニットテスト — Test.createTestingModule

NestJS は @nestjs/testing でテスト用の DIコンテナを提供します。Test.createTestingModule({ providers: [...] }) でテスト専用のモジュールを組み立て、.compile() した後 module.get(UsersService) で対象のインスタンスを取り出します。テストランナーには Jest を使うのが既定で、describe / it / expect でアサーションを書きます。

実務でのサービス単体テストの定石は、対象サービスが依存する他のプロバイダ(リポジトリや外部 API クライアントなど)をモックに差し替えることです。providers に { provide: UsersRepository, useValue: モック } のように useValue でモックを登録すれば、本物の DB に触れずにロジックだけを検証できます。既存モジュールの構成を流用しつつ一部だけ差し替えたいときは overrideProvider(Token).useValue(モック) が便利です。

つまずきポイントは、何をモックすべきかの線引きです。テスト対象そのものは本物を使い、それが依存するものだけをモックにします。すべてをモックにすると「モックが返す値を確認しているだけ」で実ロジックを検証できません。また Scope.REQUEST なプロバイダは module.get では取り出せず resolve を使うなど、スコープによって取り出し方が変わる点にも注意します。

サンプルコード(フレームワーク環境が必要なため表示のみ)

import { Test, TestingModule } from "@nestjs/testing";
import { UsersService } from "./users.service";
import { UsersRepository } from "./users.repository";

describe("UsersService", () => {
  let service: UsersService;
  // 依存(リポジトリ)はモックに差し替える
  const repoMock = { findOne: jest.fn() };

  beforeEach(async () => {
    const moduleRef: TestingModule = await Test.createTestingModule({
      providers: [
        UsersService, // テスト対象は本物
        { provide: UsersRepository, useValue: repoMock }, // 依存はモック
      ],
    }).compile();

    service = moduleRef.get<UsersService>(UsersService);
  });

  it("finds a user by id", async () => {
    repoMock.findOne.mockResolvedValue({ id: 1, name: "Alice" });
    const user = await service.findOne(1);
    expect(user.name).toBe("Alice");
  });
});
サンプルコードで身につける(5本) →

学んだ概念を、素朴な例から実務寄りの例まで5つの具体例で確認します。

公式ドキュメントで詳しく ↗