본문 바로가기

Web Dev/Javascript

Nest.js의 내장된 코드 테스트 기능 ! Jest 로 하는 유닛테스트 , e2e 테스트

반응형

https://jestjs.io/

 

Jest

By ensuring your tests have unique global state, Jest can reliably run tests in parallel. To make things quick, Jest runs previously failed tests first and re-organizes runs based on how long test files take.

jestjs.io

JEST

JEST는 자바스크립트 코드, 특히 React 애플리케이션을 테스트하기 위한 테스팅 프레임워크입니다. Facebook에서 개발하였으며, 주요 특징은 아래와 같습니다.

  1. 단순성 (Simplicity) : 별도의 설정없이 바로 테스트 코드 작성이 가능합니다.
  2. 속도 (Speed) : 병렬 실행을 통해 테스트 속도가 매우 빠릅니다.
  3. 스냅샷 테스팅 (Snapshot Testing) : 렌더링된 UI 컴포넌트의 스냅샷을 찍어서 이전 스냅샷과 비교하여 변경 사항을 감지합니다.
  4. 강력한 Mocking 기능 : 의존성을 가진 모듈들을 쉽게 Mocking할 수 있습니다.
  5. 코드 커버리지 : 테스트 케이스가 소스 코드를 얼마나 커버하는지 리포트를 제공합니다.

Jest는 create-react-app으로 만든 앱에 기본으로 포함되어 있어 리액트 프로젝트에서 광범위하게 사용되며, Vue.js, Angular, Node 등 자바스크립트 기반의 다양한 프로젝트의 테스트에도 활용되고 있는 인기 테스팅 도구입니다. 유닛 테스트, 통합 테스트, 스냅샷 테스트 등을 지원하여 코드의 정확성과 안정성을 높이는데 기여합니다.

Nest.js 는 파일을 Nest.js 시스템을 통해 생성하면 자동으로 spec.ts  테스트용 파일도 만들어 준다. 

내부 구성은 이와 같다 

import { Test, TestingModule } from '@nestjs/testing';
import { MoviesService } from './movies.service';

describe('MoviesService', () => {
  let service: MoviesService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [MoviesService],
    }).compile();

    service = module.get<MoviesService>(MoviesService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });
});

test를 하나 추가 해주자 

  it('should be 4', () => {
    expect(2 + 2).toEqual(4);
  });

여기서 it 은 아마도 Individual Test ?  

npm run test:watch

 it('should be 4', () => {
    expect(2 + 2).toEqual(5);
  });

틀린 답을 넣어 놓고 테스트를 시작하면 어떻게 될까 ? 

어떤 값이 나왔고 어떤 부분이 틀렸는지 완전 상세하게 나온다. 

  describe('getAll', () => {
    it('should return an array', () => {
      const result = service.getAll();
      expect(result).toBeInstanceOf(Array);
    });
  });

진짜 함수로 테스트 해보자 

import { Test, TestingModule } from '@nestjs/testing';
import { MoviesService } from './movies.service';
import exp from 'constants';
import { NotFoundException } from '@nestjs/common';

describe('MoviesService', () => {
  let service: MoviesService;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      providers: [MoviesService],
    }).compile();

    service = module.get<MoviesService>(MoviesService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  describe('getAll', () => {
    it('should return an array', () => {
      const result = service.getAll();
      expect(result).toBeInstanceOf(Array);
    });
  });
  describe('getOne', () => {
    it('should return a movie', () => {
      service.create({
        title: 'Test Movie',
        genres: ['test'],
        year: 2000,
      });

      const movie = service.getOne(1);
      expect(movie).toBeDefined();
      expect(movie.id).toEqual(1);
    });
    it('should throw 404 error', () => {
      try {
        service.getOne(999);
      } catch (e) {
        expect(e).toBeInstanceOf(NotFoundException);
        expect(e.message).toEqual('Movie with ID 999 not found');
      }
    });
  });
});

이런 식으로 내가 작성한 함수 하나하나를 테스트 해볼 수 있다 . 

spec.ts 파일을 통해 유닛 테스트를 해보았다 .

e2e 테스트는 뭘까? 

해당 폴더를 보면 된다. 

app.e2e-spec.ts

import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common';
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!');
  });
});

API 테스트를 통해서 값이 잘 가져와지는지 테스트 하는 코드인것 같다 

npm run test:e2e

명령어로 테스트를 시작하면 

FAIL  test/app.e2e-spec.ts
  AppController (e2e)
    × / (GET) (508 ms)                                                                                                                                                                                        
                                                                                                                                                                                                              
  ● AppController (e2e) › / (GET)                                                                                                                                                                             
                                                                                                                                                                                                              
    expected 'Hello World!' response body, got 'Welcome to my Movie API'

      20 |       .get('/')
      21 |       .expect(200)
    > 22 |       .expect('Hello World!');
         |        ^
      23 |   });
      24 | });
      25 |

      at Object.<anonymous> (app.e2e-spec.ts:22:8)
      ----
      at error (../node_modules/supertest/lib/test.js:335:15)
      at Test._assertBody (../node_modules/supertest/lib/test.js:206:16)
      at ../node_modules/supertest/lib/test.js:308:13
      at Test._assertFunction (../node_modules/supertest/lib/test.js:285:13)
      at Test.assert (../node_modules/supertest/lib/test.js:164:23)
      at Server.localAssert (../node_modules/supertest/lib/test.js:120:14)

Test Suites: 1 failed, 1 total                                                                                                                                                                                
Tests:       1 failed, 1 total                                                                                                                                                                                
Snapshots:   0 total
Time:        5.037 s
Ran all test suites.

이와 같은 에러가 발생한다. 

당연히 나의 get API 에서 응답하는 값과 expect 값이 달라서 그렇다 .

it('/ (GET)', () => {
    return request(app.getHttpServer())
      .get('/')
      .expect(200)
      .expect('Welcome to my Movie API');
  });

내 것에 맞게 수정해준다 .

> hi-nest@0.0.1 test:e2e
> jest --config ./test/jest-e2e.json

 PASS  test/app.e2e-spec.ts
  AppController (e2e)
    √ / (GET) (391 ms)                                                                                                                                                                                        
                                                                                                                                                                                                              
Test Suites: 1 passed, 1 total                                                                                                                                                                                
Tests:       1 passed, 1 total                                                                                                                                                                                
Snapshots:   0 total
Time:        4.489 s, estimated 5 s
Ran all test suites.

문제 없이 잘 통과된다. 

GET /  POST

 

  describe('/movies', () => {
    it('GET', () => {
      return request(app.getHttpServer()).get('/movies').expect(200).expect([]);
    });

    it('POST', () => {
      return request(app.getHttpServer())
        .post('/movies')
        .send({ title: 'Test', year: 2000, genres: ['action'] })
        .expect(201);
    });
  });

todo 기능을 사용해보자 

  describe('/movies/:id', () => {
    it.todo('GET');
    it.todo('DELETE');
    it.todo('PATCH');
  });

해당 코드를 추가하면 

이와 같은 결과 값이 나온다. 

it.todo는 Jest에서 제공하는 테스트 작성 함수 중 하나입니다. 테스트 케이스를 작성할 때 it 함수를 사용하는데, it.todo는 미래에 작성해야 할 테스트 케이스를 표시하는 역할을 합니다.

it.todo를 사용하면 실제로 테스트 코드를 작성하지 않고도 테스트 케이스의 설명만 작성할 수 있습니다. 이는 테스트 계획을 세울 때 유용하게 사용될 수 있습니다.

반응형