Skip to main content
Практика завдань

Як протестувати додаток NestJS?

Тестування додатків NestJS

NestJS за замовчуванням використовує Jest і надає пакет @nestjs/testing для створення ізольованих тестових модулів. Фреймворк підтримує як модульні тести (ізольовані тести сервісів/контролерів), так і тести кінцевих точок (e2e) (повний стек HTTP).


Модульне тестування сервісу

typescript
// users/users.service.spec.ts import { Test, TestingModule } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { UsersService } from './users.service'; import { User } from './entities/user.entity'; import { NotFoundException } from '@nestjs/common'; describe('UsersService', () => { let service: UsersService; let repo: jest.Mocked<Repository<User>>; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ UsersService, { provide: getRepositoryToken(User), useValue: { find: jest.fn(), findOneBy: jest.fn(), create: jest.fn(), save: jest.fn(), delete: jest.fn(), }, }, ], }).compile(); service = module.get<UsersService>(UsersService); repo = module.get(getRepositoryToken(User)); }); describe('findOne()', () => { it('повинен повернути користувача, коли знайдено', async () => { const user: User = { id: 1, name: 'Alice', email: 'alice@test.com' } as User; repo.findOneBy.mockResolvedValue(user); const result = await service.findOne(1); expect(result).toEqual(user); expect(repo.findOneBy).toHaveBeenCalledWith({ id: 1 }); }); it('повинен кинути NotFoundException, коли не знайдено', async () => { repo.findOneBy.mockResolvedValue(null); await expect(service.findOne(99)).rejects.toThrow(NotFoundException); }); }); describe('create()', () => { it('повинен створити і повернути користувача', async () => { const dto = { name: 'Bob', email: 'bob@test.com' }; const user = { id: 2, ...dto } as User; repo.create.mockReturnValue(user); repo.save.mockResolvedValue(user); const result = await service.create(dto); expect(result).toEqual(user); }); }); });

Модульне тестування контролера

typescript
// users/users.controller.spec.ts describe('UsersController', () => { let controller: UsersController; let service: jest.Mocked<UsersService>; beforeEach(async () => { const module = await Test.createTestingModule({ controllers: [UsersController], providers: [ { provide: UsersService, useValue: { findAll: jest.fn().mockResolvedValue([]), findOne: jest.fn(), create: jest.fn(), }, }, ], }).compile(); controller = module.get<UsersController>(UsersController); service = module.get(UsersService); }); it('повинен повернути масив з findAll()', async () => { const result = await controller.findAll(); expect(result).toEqual([]); expect(service.findAll).toHaveBeenCalled(); }); });

E2E Тестування

typescript
// test/users.e2e-spec.ts import * as request from 'supertest'; describe('UsersController (e2e)', () => { let app: INestApplication; beforeAll(async () => { const moduleFixture = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = moduleFixture.createNestApplication(); app.useGlobalPipes(new ValidationPipe({ whitelist: true })); await app.init(); }); afterAll(async () => await app.close()); it('GET /users → 200', () => { return request(app.getHttpServer()) .get('/users') .expect(200) .expect(res => { expect(Array.isArray(res.body)).toBe(true); }); }); it('POST /users → 201 з дійсним тілом', () => { return request(app.getHttpServer()) .post('/users') .send({ name: 'Alice', email: 'alice@test.com' }) .expect(201); }); it('POST /users → 400 з недійсним тілом', () => { return request(app.getHttpServer()) .post('/users') .send({ name: 'A' }) // занадто коротко, немає email .expect(400); }); });

Тестування охоронців

typescript
// Переопределити охоронця в тесті const module = await Test.createTestingModule({ controllers: [UsersController], providers: [UsersService], }) .overrideGuard(JwtAuthGuard) .useValue({ canActivate: () => true }) // завжди дозволяти .compile();

Резюме

Тестування NestJS використовує Test.createTestingModule() для побудови ізольованих контекстів модулів. Для модульних тестів підробляйте залежності за допомогою jest.fn(). Для e2e тестів створюйте повний додаток за допомогою app.init() і використовуйте Supertest для HTTP запитів. Переоприділяйте охоронців/труби/інтерсептори за допомогою .overrideGuard(), .overridePipe() тощо.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань