포시코딩

테스트 코드(Test Code) - supertest 본문

Test Case

테스트 코드(Test Code) - supertest

포시 2023. 1. 8. 17:42
728x90

설치

npm i jest supertest -D

 

jest 옵션 설정

jest.config.js

module.exports = {
  // 해당 패턴에 일치하는 경로가 존재할 경우 테스트를 하지 않고 넘어간다.
  "testPathIgnorePatterns": ["/node_modules/"],
  // 테스트 실행 시 각 TestCase에 대한 출력을 해준다.
  verbose: true,
}

더 자세한 Jest config에 대해서는 [링크] 참고

 

이번에는 package.json에서 Jest CLI 옵션을 추가한 jest script를 선언해보자

package.json

{
  "scripts": {
    "test": "jest --forceExit",
    "test:silent": "jest --silent --forceExit",
    "test:coverage": "jest --coverage --forceExit",
    "test:unit": "jest __tests__/unit --forceExit",
    "test:integration": "jest __tests__/integration --forceExit"
  },
}

 

--forceExit

  • 테스트 코드 검사가 완료되었을 때, 강제로 Jest 종료
  • express의 app 객체와 Sequelize 연결이 connect 상태로 남아있어 테스트 코드가 종료되지 않을 때 사용

--silent

  • 테스트 코드를 실행했을 때, console.log와 같은 메시지를 출력하지 않는다.

--coverage

  • 테스트 코드 검사가 완료된 후 현재 프로젝트의 테스트 코드 커버리지를 출력한다.

--verbose

  • 테스트 코드의 개별 테스트 결과를 표시해준다.
  • 테스트 결과를 명확하게 볼 수 있어 디버깅할 때 유용하므로 웬만하면 설정해준다.

그 외 Jest CLI Option은 [링크] 참고

 

Jest 문법

자주 사용하는 Jest 문법에 대해 정리해보자

expect 결과값 검증

.toEqual(value)

  • 입력받은 결과값과 동일한지 비교한다.

 .toBe(value)

  • 입력받은 결과값과 동일한지 비교한다.
  • 만약 Instance를 비교한다면 Instance의 id까지 비교하므로 '엄격하게' 동일한지 검증한다.

.toMatch(regexp | String)

  • 입력받은 결과값과 문자열이 같은지 검증한다.
  • String 또는 정규표현식으로 검증할 수 있다.

.toBeTruthy()

  • 결과값이 True인지 검증한다.

.toBeInstanceOf(Class)

  • 입력받은 값과 Class가 동일한 Instance인지 검증한다.
  • Error를 검증할 때 주로 사용한다.

.toHaveProperty(keyPath, value?)

  • 입력받은 객체의 key와 value가 일치하는지 검증한다.

.toMatchObject(Object)

  • 결과값의 객체와 입력받은 객체가 일치하는지 검증한다.
  • 만약 입력받은 객체에서 없는 속성이 있더라도 일치하게끔 연결한다.

.anything()

  • null, undefined와 일치하는지 검증한다.
  • 특정 시간을 기준으로 만들어지는 createAt, updatedAt과 같이
    객체의 특정 parameter가 존재하는지에 대한 여부를 검증하기 위해 사용한다.

 

Global Jest 문법

afterAll(fn, timeout)

  • 모든 test()가 완료된 이후에 수행된다.
  • 테스트가 완료된 이후 DB에 변경된 데이터를 삭제하거나 Mock을 초기화 하기 위해 사용된다.

afterEach(fn, timeout)

  • test()가 완료된 이후에 수행된다.
  • 테스트 코드가 완료된 이후 Mock 또는 변경된 전역 변수를 초기화 할 때 사용된다.

beforeAll(fn, timeout)

  • 테스트 코드가 실행되기 전 가장 처음 수행된다.
  • DB의 데이터를 초기화하거나 전역 Mock을 초기화 할 때 사용된다.

beforeEach(fn, timeout)

  • test()가 실행되기 전에 수행된다.
  • 테스트가 실행되기 전, 동일한 설정을 반복해야 할 때 사용된다.

 

Mock Function

Mock이란 특정 Method를 Mocking하기 위해 사용된다.

즉, 테스트에서 시간 또는 비용이 많이 들거나 의존성이 있는 코드를 실제로 실행하지 않고

호출 여부, 입력한 값의 일치 여부와 같은 정보를 확인하기 위해 사용하는 가짜 객체다.

 

자주 사용하는 Mock expect 문법

.toHaveBeenCalledTimes(number)

  • Mock이 몇번 호출되었는지 검증한다.

.toHaveBeenCalledWith(arg1, arg2, ...)

  • 어떤 인자를 이용해 Mock이 호출되었는지 검사한다.

그 외 Jest Mock Function [링크]

 

supertest

supertest는 jest와 함께 사용하여 부분적인 테스트 뿐만 아니라,

원하는 요청(request)를 이용해 반환(response)된 정보를 검증하기 위해 사용되는 대표적인 

테스트 라이브러리다.

 

사용 예시

const supertest = require("supertest");
const app = require("../../app.js");

const response = await supertest(app)
  .post(`/api/posts`) // API의 HTTP Method & URL
  .query({}) // Request Query String
  .send({}) // Request Body

 

supertest 문법

.post('URI')

  • Http Method와 URI를 입력해 테스트 하려는 API를 호출할 수 있다.

.query(Object)

  • API에게 Query String을 이용해 데이터를 전달한다.

.send(Object)

  • API에게 Body의 데이터를 전달한다.

response: supertest를 이용해 API를 수행한 response값이 할당된다.

  • response.type: response header의 content-type의 값
  • response.body: API response에 반환된 json 데이터
  • response.headers: API response에 반환된 헤더 정보

* 그 외 response의 다양한 반환 값 [링크] 참고

 

Sequelize Test DB 설정

config/config.json에서 "test"에 해당하는 정보를 세팅해준 뒤 아래 명령어 입력

NODE_ENV=test npx sequelize db:create
NODE_ENV=test npx sequelize db:migrate

사용 예시

const supertest = require('supertest');
const app = require('../../app.js');
const { sequelize } = require('../../models/index.js');

// 통합 테스트(Integration Test)를 진행하기에 앞서 Sequelize에 연결된 모든 테이블의 데이터를 삭제
//  단, NODE_ENV가 test 환경으로 설정되어있는 경우에만 데이터를 삭제
beforeAll(async () => {
  if (process.env.NODE_ENV === 'test') await sequelize.sync();
  else throw new Error('NODE_ENV가 test 환경으로 설정되어 있지 않습니다.');
});


describe('Layered Architecture Pattern, Posts Domain Integration Test', () => {
  test('GET /api/posts API (getPosts) Integration Test Success Case, Not Found Posts Data', async () => {
    const response = await supertest(app)
      .get(`/api/posts`) // API의 HTTP Method & URL
      .query({}) // Request Query String
      .send({}) // Request Body
  });

  test('some case', async () => {
    // TODO: 여기에 코드를 작성
  });
});


afterAll(async () => {
  // 통합 테스트가 완료되었을 경우 sequelize의 연결된 테이블들의 정보를 초기화
  if (process.env.NODE_ENV === 'test') await sequelize.sync({ force: true });
  else throw new Error('NODE_ENV가 test 환경으로 설정되어 있지 않습니다.');
});

sequelize.sync 문법

sequelize.sync()

  • 테이블이 없는 경우 새롭게 생성한다. 
    하지만, 테이블이 이미 존재하면 아무 행동도 하지 않는다.

sequelize.sync({ force: true })

  • 테이블을 생성하고, 만약 테이블이 이미 존재한다면 삭제한 후 다시 생성한다.

beforeAll() 로직

beforeAll(async () => {
  if (process.env.NODE_ENV === 'test') await sequelize.sync();
  else throw new Error('NODE_ENV가 test 환경으로 설정되어 있지 않습니다.');
});
  • sequelize.sync()를 수행하여 test 환경에 있는 MySQL의 테이블을 생성한다.
  • test 환경이 아닐 때는 에러를 발생하여 테스트 코드가 실패하도록 작성되어 있다.
  • 테이블이 존재하지 않아 통합 테스트가 실패하는 경우를 방지할 수 있다.

afterAll() 로직

afterAll(async () => {
  if (process.env.NODE_ENV === 'test') await sequelize.sync({ force: true });
  else throw new Error('NODE_ENV가 test 환경으로 설정되어 있지 않습니다.');
});
  • sequelize.sync({ force: true })를 수행하여 test 환경에 있는 MySQL의 테이블들을 삭제 후 생성(초기화)한다.
  • test 환경이 아닐 때는 에러를 발생하여 MySQL의 테이블 삭제를 방지한다.
  • 다음 테스트 코드를 실행할 때, DB의 환경을 처음과 같은 상태로 만들어 편리하게 테스트 코드를 작성할 수 있다.

 

 

 

 

테스트 코드 사용 예제

https://github.com/cchoseonghun/Layered_Architecture_Pattern_With_Test

 

GitHub - cchoseonghun/Layered_Architecture_Pattern_With_Test: 계층형 아키텍처 패턴에서의 테스트 코드 작성 연

계층형 아키텍처 패턴에서의 테스트 코드 작성 연습 프로젝트. Contribute to cchoseonghun/Layered_Architecture_Pattern_With_Test development by creating an account on GitHub.

github.com

https://github.com/9hezo/save_my_keyboard/tree/dev/app/__tests__

 

GitHub - 9hezo/save_my_keyboard

Contribute to 9hezo/save_my_keyboard development by creating an account on GitHub.

github.com

728x90

'Test Case' 카테고리의 다른 글

[Jest] mockImplementation, mockResolvedValue  (0) 2023.07.17
[Jest] 오토 모킹 vs 수동 모킹  (0) 2023.04.02
테스트 코드(Test Code) - Jest  (0) 2022.12.31
assert문이란?  (0) 2022.11.19
코드 커버리지(Code Coverage)란?  (0) 2022.11.19