Learn NestJS - Testing & Quality Assurance
Episode 17 of 24

Learn NestJS - Testing & Quality Assurance

This episode covers testing in NestJS: unit testing with Jest, integration testing using @nestjs/testing, E2E testing and test database setup, plus code coverage, linting, and static analysis to maintain code quality.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Introduction

An application without tests is a ticking time bomb. NestJS is designed with testing as a priority — dependency injection makes replacing dependencies with mocks very easy. Episode 17 covers unit tests, integration tests, and E2E tests to build the habit of writing tests that maintain code quality.

Unit Testing with Jest

Test Setup

The Nest CLI already configures Jest when creating a project. To run tests:

Menjalankan unit test
npm run test

Jest finds files ending with .spec.ts and runs them — invoke it with npm run test.

Writing a Unit Test for a Service

A unit test focuses on a single unit — for example a service, with dependencies mocked:

JSUnit test untuk UsersService
import { Test } from "@nestjs/testing";
import { UsersService } from "./users.service";
 
describe("UsersService", () => {
  let service: UsersService;
 
  beforeEach(async () => {
    const moduleRef = await Test.createTestingModule({
      providers: [UsersService],
    }).compile();
 
    service = moduleRef.get(UsersService);
  });
 
  it("harus mengembalikan daftar user", () => {
    const result = service.findAll();
    expect(result).toContain("Arman");
  });
});

Test.createTestingModule creates a testing module that mirrors the runtime. it and expect are built-in Jest APIs.

Mocking Dependencies

When a service depends on a repository, replace the real dependency with useValue:

JSMocking repository
const mockRepo = {
  find: jest.fn().mockResolvedValue([{ id: 1, name: "Arman" }]),
};
 
const moduleRef = await Test.createTestingModule({
  providers: [UsersService, { provide: "UserRepository", useValue: mockRepo }],
}).compile();

With useValue, real dependencies are replaced with mocks — tests become fast and isolated from the database.

Integration Testing with @nestjs/testing

Testing a Full Module

Integration tests combine several real components — controllers, services, and modules — while still mocking external dependencies like the database.

JSIntegration test controller + service
describe("UsersController", () => {
  let controller: UsersController;
 
  beforeEach(async () => {
    const moduleRef = await Test.createTestingModule({
      controllers: [UsersController],
      providers: [
        UsersService,
        { provide: "UserRepository", useValue: mockRepo },
      ],
    }).compile();
 
    controller = moduleRef.get(UsersController);
  });
 
  it("harus mengembalikan user", async () => {
    const result = await controller.findAll();
    expect(result).toHaveLength(1);
  });
});

Overriding Providers

NestJS provides .overrideProvider().useValue() to replace a provider during testing — useful when testing a full module without running heavy dependencies.

E2E Testing

End-to-End Testing

E2E tests bootstrap the entire application and send real HTTP requests using supertest:

JSSetup E2E test
import * as request from "supertest";
import { Test } from "@nestjs/testing";
import { INestApplication } from "@nestjs/common";
import { AppModule } from "../src/app.module";
 
describe("App (e2e)", () => {
  let app: INestApplication;
 
  beforeEach(async () => {
    const moduleRef = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();
 
    app = moduleRef.createNestApplication();
    await app.init();
  });
 
  it("GET / mengembalikan Hello World", () => {
    return request(app.getHttpServer())
      .get("/")
      .expect(200)
      .expect("Hello World!");
  });
});

Run it with npm run test:e2e. E2E files live in the test/ folder and end with .e2e-spec.ts.

Test Database Setup

For E2E tests that touch the database, use a separate test database or an in-memory one:

JSDatabase in-memory untuk test
TypeOrmModule.forRoot({
  type: "sqlite",
  database: ":memory:",
  autoLoadEntities: true,
  synchronize: true,
})

Each test starts with a clean database, making test results deterministic and fast.

Code Coverage, Linting, and Static Analysis

Code Coverage

Jest counts how much of your code is tested:

Menjalankan test dengan coverage
npm run test -- --coverage

The coverage report shows lines that aren't tested yet. A healthy target is usually 80 percent and above for critical code.

Linting and Static Analysis

NestJS uses ESLint and the TypeScript compiler to catch problems early:

Menjalankan lint
npm run lint

Linting catches style errors and common bugs. Additions like TypeScript strict mode and proper types provide an extra layer of static analysis before the code runs.

Conclusion

Episode 17 builds a testing culture. Key takeaways:

  • Test.createTestingModule creates a testing module like the runtime.
  • Unit tests focus on a single unit and mock its dependencies.
  • E2E tests send real HTTP requests with supertest.
  • In-memory databases make tests fast and deterministic.
  • Coverage, ESLint, and TypeScript strict mode maintain code quality.
Learn NestJS - Testing & Quality Assurance | Learning NestJS