NestJS

Lesson 10

Testing module overrides

Use NestJS testing modules and provider overrides so tests exercise application wiring without real infrastructure.

Good Code

reviews.service.spec.ts
import { Test } from "@nestjs/testing";

it("returns pending reviews", async () => {
  const repository = { findByStatus: vi.fn().mockResolvedValue([]) };

  // The testing module replaces infrastructure at the provider boundary.
  const moduleRef = await Test.createTestingModule({
    providers: [ReviewsService, { provide: REVIEWS_REPOSITORY, useValue: repository }],
  }).compile();

  const service = moduleRef.get(ReviewsService);
  await service.findPending();

  expect(repository.findByStatus).toHaveBeenCalledWith("pending");
});

Bad Code

reviews.service.spec.ts
it("returns pending reviews", async () => {
  const service = new ReviewsService();

  // The test patches a private field after construction.
  (service as any).reviews = { findByStatus: vi.fn().mockResolvedValue([]) };

  await service.findPending();
});

Review Notes

What to review

Good Code

The good version builds a testing module and replaces the repository provider. The test uses the same injection path as the application.

Bad Code

The bad version constructs the service manually and writes a private dependency after the fact. That can hide broken module registration.

Takeaways

  • A test should replace external providers at the module boundary instead of reaching into service internals.