Testing is an essential aspect of modern software development that ensures your application works as intended. In a powerful framework like NestJS, using Jest as a testing framework can seem daunting at first, but it’s an excellent choice that integrates seamlessly into your workflow. This guide will walk you through setting up Jest for testing in a NestJS application, the various types of tests you can perform, and how to write effective tests.
NestJS is a progressive Node.js framework for building efficient and scalable server-side applications. It leverages TypeScript, which brings in static typing that helps catch errors during development. On the other hand, Jest is a delightful JavaScript testing framework that provides a smooth experience for writing tests with a rich ecosystem.
Before we dive into writing tests, we need to ensure that Jest is correctly set up in our NestJS application. The first step is to install Jest along with the necessary packages for TypeScript support.
In your NestJS project, run the following command:
npm install --save-dev jest @nestjs/testing ts-jest @types/jest
Then, create a Jest configuration file. You can do this by adding a jest.config.js
file to your project root:
module.exports = { moduleFileExtensions: ['js', 'json', 'ts'], rootDir: 'src', testRegex: '.spec.ts$', transform: { '^.+\\.(t|j)s$': 'ts-jest', }, collectCoverage: true, coverageDirectory: '../coverage', testEnvironment: 'node', };
This configuration specifies that Jest should look for files ending in .spec.ts
in the src
directory, use ts-jest
to transpile TypeScript code, and collect coverage information.
Let’s create our first simple test to demonstrate how the testing process works in NestJS. Suppose we have a simple service that manages a list of users.
Here's how the user service might look in user.service.ts
:
import { Injectable } from '@nestjs/common'; @Injectable() export class UserService { private users: string[] = []; addUser(name: string): void { this.users.push(name); } getUsers(): string[] { return this.users; } }
Unit tests focus on testing individual parts of your application in isolation. Here is how to write unit tests for the UserService
.
First, create a file named user.service.spec.ts
:
import { Test, TestingModule } from '@nestjs/testing'; import { UserService } from './user.service'; describe('UserService', () => { let service: UserService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [UserService], }).compile(); service = module.get<UserService>(UserService); }); it('should be defined', () => { expect(service).toBeDefined(); }); it('should add a user', () => { service.addUser('John Doe'); expect(service.getUsers()).toContain('John Doe'); }); it('should return all users', () => { service.addUser('Jane Doe'); service.addUser('John Doe'); expect(service.getUsers()).toEqual(['Jane Doe', 'John Doe']); }); });
beforeEach
function to set up our testing module and instantiating the UserService
before each test runs.addUser
method works as expected and that we can retrieve the users correctly.Integration tests, unlike unit tests, focus on testing how various parts of your application work together. Let’s see how to write an integration test for our user service.
Let’s add a simple controller to handle user requests in user.controller.ts
:
import { Controller, Get, Post, Body } from '@nestjs/common'; import { UserService } from './user.service'; @Controller('users') export class UserController { constructor(private userService: UserService) {} @Post() addUser(@Body('name') name: string) { this.userService.addUser(name); } @Get() getUsers() { return this.userService.getUsers(); } }
Now, create a file named user.controller.spec.ts
:
import { Test, TestingModule } from '@nestjs/testing'; import { UserController } from './user.controller'; import { UserService } from './user.service'; describe('UserController', () => { let controller: UserController; let service: UserService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ controllers: [UserController], providers: [UserService], }).compile(); controller = module.get<UserController>(UserController); service = module.get<UserService>(UserService); }); it('should be defined', () => { expect(controller).toBeDefined(); }); it('should call addUser method in UserService', async () => { const addUserSpy = jest.spyOn(service, 'addUser'); await controller.addUser({ name: 'John Doe' }); expect(addUserSpy).toHaveBeenCalledWith('John Doe'); }); it('should return users from UserService', async () => { jest.spyOn(service, 'getUsers').mockReturnValue(['John Doe']); expect(await controller.getUsers()).toEqual(['John Doe']); }); });
UserController
and UserService
.addUser
method of UserService is called with the correct user name.getUsers
method to ensure it returns the expected users.To run your tests, simply execute the following command:
npm run test
This will look for files matching .spec.ts
and run the tests you've created, providing you detailed output on each test’s progress and results.
Testing is a critical skill to cultivate as a developer, especially in a structured framework like NestJS. It not only helps ensure that individual components operate correctly but also that they work harmoniously together, thereby creating a robust backend application. By following the examples and principles outlined in this guide, you will be well on your way to incorporating efficient testing practices in your NestJS projects.
10/12/2024 | NestJS
10/12/2024 | NestJS
10/12/2024 | NestJS
10/12/2024 | NestJS
10/12/2024 | NestJS
10/12/2024 | NestJS
10/12/2024 | NestJS
10/12/2024 | NestJS