Introduction
Testing is a critical step in the software development process. In this tutorial, we leverage Jest and Supertest to create reliable unit tests for applications built with NestJS, a Node.js framework. Learn how to ensure your NestJS services and controllers behave as expected under various conditions.
Setting Up the Environment
To start writing unit tests in NestJS, you must first set up your environment:
// Install Jest and the testing tools
$ npm install --save-dev @nestjs/testing jest @types/jest ts-jest
$ npm install --save-dev supertest @types/supertest
// Add a jest.config.js file
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
};
// Add the following scripts to your package.json
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
}
With Jest and Supertest installed, and the configuration in place, you’re ready to begin unit testing your NestJS application.
Testing NestJS Services
Begin with testing your services:
import { Test, TestingModule } from '@nestjs/testing';
import { MyService } from './my.service';
describe('MyService', () => {
let service: MyService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [MyService],
}).compile();
service = module.get(MyService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
// Add more tests here
});
This is a simple test to check that the service is properly instantiated.
Testing Controllers with Supertest
Moving forward, combine efforts with Supertest to test controllers:
import { INestApplication } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => {
let app: INestApplication;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!');
});
afterEach(async () => {
await app.close();
});
});
Here we’re using Supertest to perform end-to-end tests on the application’s endpoint.
Mocking Dependencies
Mocking is essential for isolating tests. NestJS provides tools for easy mocking:
import { MyService } from './my.service';
describe('MyService', () => {
let service: MyService;
let mockRepository: MockRepository;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
MyService,
{
provide: MyRepository,
useClass: MockRepository
}
],
}).compile();
service = module.get(MyService);
mockRepository = module.get(MyRepository);
});
// Tests using the mocked repository here
});
Create realistic and controlled conditions by using mocked versions of your dependencies.
You can further enhance your unit tests by simulating more complex scenarios. NestJS’s powerful testing utilities enable developers to craft thorough test suites that cover all logic branches.
Creating Test Suites
While individual tests are useful, grouping similar tests into suites provides better organization and readability:
// Individual test suites with their own beforeEach, afterEach, and collection of `it` blocks for a comprehensive testing strategy
Use Jest’s powerful test suite capabilities to ensure every aspect of your NestJS application is verified.
Handling Asynchronous Code
In a Node.js environment, dealing with asynchronous operations is the norm. Here’s how you can test asynchronous service methods in NestJS:
it('should do async operation', async () => {
await expect(service.someAsyncMethod()).resolves.toEqual(expectedOutcome);
});
Ensure your async functions behave as intended by properly resolving promises and managing exceptions.
Applying TDD
Test-Driven Development (TDD) is an approach where you write tests first, before coding the actual feature. Applying TDD with NestJS and Jest can significantly improve the quality and maintainability of your code.
Conclusion
Unit testing is a vital part of NestJS application development, ensuring your codebase is robust and functionally correct. With Jest and Supertest, NestJS apps can benefit from efficient, expressive, and powerful testing suites. By following this tutorial, you’re well on your way to mastering unit tests in your NestJS applications.