IT/DEV Study

[Nomad Corders] NestJS로 API 만들기 #3 정리

Ella.J 2022. 7. 26. 17:43
728x90
반응형

2022.07.25 - [IT] - [Nomad Corders] NestJS로 API 만들기 #2.4 to #2.7 정리

 

[Nomad Corders] NestJS로 API 만들기 #2.4 to #2.7 정리

2022.07.25 - [IT] - [Nomad Corders] NestJS로 API 만들기 #2.0 to #2.3 정리 [Nomad Corders] NestJS로 API 만들기 #2.0 to #2.3 정리 #2 REST API #2.0 Movies Controller #2.1 More Routes #2.2 Movies Servic..

ella-devblog.tistory.com


#3 UNIT TESTING

 

#3.0 Introduction to Testing in Nest

package.json 파일에 보면 테스팅과 관련된 5 항목을 있음.

jest : 자바스크립트를 아주 쉽게 테스팅하는 npm 패키지.

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 is a delightful JavaScript Testing Framework with a focus on simplicity."

 

.spec.ts : test module 포함한 파일.

ex) movies controller 테스트하기 위해서는 movies.controller.spec.ts 파일이 있어야함.

NestJs에서는 jest가 .spec.ts 파일들을 찾아볼 있도록 설정되어 있음.

[>npm run test:cov] 통해서 테스트 결과 값과 coverage(적용 범위) 값을 알 수 있음.

"test:cov":"jest --coverage"

테스트 PASS/FAIL 로 결과가 나옴.

 

[>npm run test:watch] 입력하면 Watch Usage 어떤 것을 실행할 것인지 물어봄.

"test:watch":"jest --watch"

a 눌러 파일에 변경점이 있을 때 마다 모든 테스트를 실행.

실행 중 화면.
실행 완료 화면.

* Unit Testing : 모든 function 따로 테스트하는 . 서비스에서 분리된 유닛을 테스트하는 .

* End-to-End(e2e) Testing : Whole System Testing. 전체 시스템 테스팅.

자동으로 e2e test 폴더가 생성됨.

ex) Unit Testing getAll() or getOne() 등 function 하나씩 테스트할 때 사용.

ex) e2e Testing 페이지로 가면 특정 페이지가 나와야하는 경우 사용. 사용자가 사용할만한 것들을 테스트.


728x90

#3.1 Your first Unit Test

 

movies.service.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', () => { //it : indivisual test

    expect(service).toBeDefined();

  });

  //let me create

  it("should be 4", () => {

    expect(2+2).toEqual(4) //2+2 4와 같기(toEqual)를 기대(expect)하고 있어

  } )

});

 

파일을 위와 같이 수정하고, test:watch 통해서 단위테스트를 해보자.

실행결과 우리가 추가한 should be 4 문제없이 pass됨.

 

만약, expect(2+2).toEqual(5) 요렇게 바꾸면,

테스트에 실패했다고 나오고, 어떤 값이 나와야하는지까지 알려줌.


#3.2 Testing getAll and getOne

그럼 이제, 우리가 movies.service.ts 에서 사용하고 있는 함수들의 Unit Test 단위 테스트 작성해보자.

다섯가지 함수에 관한 단위테스트를 작성해 볼게~

 

[getAll 함수 테스트]

  //getAll 함수의 결과값이 Array 인지 테스트

  describe("getAll", () => {

    it("should return an array", () => {

      const result = service.getAll();

      expect(result).toBeInstanceOf(Array);

    });

  });

 

[getOne 함수 테스트]

  //getOne 함수 실행 테스트

  describe("getOne", () => {

    //결과값이 정상적으로 나오는지 테스트

    it("should return a movie", () => {

      //테스트를 위한 Movie 만들기 (없으면 에러)

      service.create({

        title:'Test Movie',

        genres: ['test'],

        year: 2000,

      });

      const movie = service.getOne(1);

      expect(1).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.');

      }

    });

  });

test:watch 결과 값.
test:cov 결과 값.

coverage 전보다 증가. 테스트 코드가 늘어나서 그럼.

Funcs 결과값을 보면 수치들이 어느 정도의 파일들을 테스트하고 있는지 알려줌.


#3.3 Testing delete and create

[deleteOne 함수 테스트]

  //deleteOne 함수 실행 테스트

  describe("deleteOne", () => {

    //삭제가 정상적인지 테스트

    it("deletes a movie", () => {

      //테스트를 위한 Movie 만들기 (없으면 에러)

      service.create({

        title:'Test Movie',

        genres: ['test'],

        year: 2000,

      });

      const beforeDelete = service.getAll().length;

      service.deleteOne(1);

      const afterDelete = service.getAll().length;

      //삭제 후의 Movie 개수 비교

      expect(afterDelete).toBeLessThan(beforeDelete);

    });

    //에러가 정상적으로 나오고 있는지 테스트

    it("should return a 404", () => {

      try {

        service.deleteOne(999);

      }catch(e){

        expect(e).toBeInstanceOf(NotFoundException)

      }

    });

  });

 

[create 함수 테스트]

  //create 함수 실행 테스트

  describe("create", () => {

    it("should create a movie", () => {

      const beforeCreate = service.getAll().length;

      service.create({

        title:'Test Movie',

        genres: ['test'],

        year: 2000,

      });

      const afterCreate = service.getAll().length;

      //create  후의 Movie 개수 비교

      expect(afterCreate).toBeGreaterThan(beforeCreate);

    });

  });


#3.4 Testing update

  • (참고) 위에서 계속 단위테스트마다 Movie 생성해줬는데, 미리 번에 생성하고 싶으면 beforeEach 안에서 만들어 주면 .

  beforeEach(async () => { //테스트 하기 전에 실행되는 곳

    const module: TestingModule = await Test.createTestingModule({

      providers: [MoviesService],

    }).compile();

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

    service.create({

      title:'Test Movie',

      genres: ['test'],

      year: 2000,

    });

  });

 

 

[update 함수 테스트]

  //update 함수 실행 테스트

  describe("update", () => {

    it("should update a movie", () => {

      service.create({

        title:'Test Movie',

        genres: ['test'],

        year: 2000,

      });

      service.update(1, {title: 'Updated Test'});

      const movie = service.getOne(1);

      expect(movie.title).toEqual('Updated Test');

    });

    //에러가 정상적으로 나오고 있는지 테스트

    it("should throw a NotFoundException", () => {

      try {

        service.update(999, {title: 'Updated Test'});

      }catch(e){

        expect(e).toBeInstanceOf(NotFoundException)

      }

    });

  });

 

반응형

[최종 movies.service.spec.ts 코드]

import { Test, TestingModule } from '@nestjs/testing';

import { MoviesService } from './movies.service';

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', () => { //it : indivisual test

    expect(service).toBeDefined();

  });

 

  //getAll 함수의 결과값이 Array 인지 테스트

  describe("getAll", () => {

    it("should return an array", () => {

      const result = service.getAll();

      expect(result).toBeInstanceOf(Array);

    });

  });

 

  //getOne 함수 실행 테스트

  describe("getOne", () => {

    //결과값이 정상적으로 나오는지 테스트

    it("should return a movie", () => {

      //테스트를 위한 Movie 만들기 (없으면 에러)

      service.create({

        title:'Test Movie',

        genres: ['test'],

        year: 2000,

      });

      const movie = service.getOne(1);

      expect(1).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.');

      }

    });

  });

 

  //deleteOne 함수 실행 테스트

  describe("deleteOne", () => {

    //삭제가 정상적인지 테스트

    it("deletes a movie", () => {

      //테스트를 위한 Movie 만들기 (없으면 에러)

      service.create({

        title:'Test Movie',

        genres: ['test'],

        year: 2000,

      });

      const beforeDelete = service.getAll().length;

      service.deleteOne(1);

      const afterDelete = service.getAll().length;

      //삭제 후의 Movie 개수 비교

      expect(afterDelete).toBeLessThan(beforeDelete);

    });

    //에러가 정상적으로 나오고 있는지 테스트

    it("should return a 404", () => {

      try {

        service.deleteOne(999);

      }catch(e){

        expect(e).toBeInstanceOf(NotFoundException)

      }

    });

  });

 

  //create 함수 실행 테스트

  describe("create", () => {

    it("should create a movie", () => {

      const beforeCreate = service.getAll().length;

      service.create({

        title:'Test Movie',

        genres: ['test'],

        year: 2000,

      });

      const afterCreate = service.getAll().length;

      //create  후의 Movie 개수 비교

      expect(afterCreate).toBeGreaterThan(beforeCreate);

    });

  });

 

  //update 함수 실행 테스트

  describe("update", () => {

    it("should update a movie", () => {

      service.create({

        title:'Test Movie',

        genres: ['test'],

        year: 2000,

      });

      service.update(1, {title: 'Updated Test'});

      const movie = service.getOne(1);

      expect(movie.title).toEqual('Updated Test');

    });

    //에러가 정상적으로 나오고 있는지 테스트

    it("should throw a NotFoundException", () => {

      try {

        service.update(999, {title: 'Updated Test'});

      }catch(e){

        expect(e).toBeInstanceOf(NotFoundException)

      }

    });

  });

});

최종 test:watch 결과.
최종 test:cov 결과.

모든 함수에 대한 테스트가 완료됐기 때문에 100퍼센트로 나옴.

 

+ (추가)

spec.ts 파일에는 beforeEach 이외에도, afterEach, beforeAll, afterAll 같은 것이 있음.

예를 들어, afterAll() 안에는 DB 깨끗하게 정리해주는(모두 지우는) function 넣을 있음.

나중에 활용 가능.

 

이번에는 Unit Testing 다뤘으면, 다음시간에는 test 폴더를 통해 e2e Testing 해보자.


2022.07.27 - [IT] - [Nomad Corders] NestJS로 API 만들기 #4 정리 (완강)

 

[Nomad Corders] NestJS로 API 만들기 #4 정리 (완강)

2022.07.26 - [IT] - [Nomad Corders] NestJS로 API 만들기 #3 정리 [Nomad Corders] NestJS로 API 만들기 #3 정리 2022.07.25 - [IT] - [Nomad Corders] NestJS로 API 만들기 #2.4 to #2.7 정리 [Nomad Corders]..

ella-devblog.tistory.com

 

728x90
반응형