유닛 테스트하기(feat. Jest) (2)

문린이·2023년 2월 28일
0

Jest란?

Jest는 Meta에서 유지 관리하는 JavaScript 테스트 라이브러리로 Node 진영에서도 많이 사용하고 있다.

Weekly Downloads가 무려 20,679,279...

Jest 사용하기

Jest 설치

npm을 통한 설치 (yarn)

# devDependencies

npm install -D jest

package.json에 추가

  "scripts": {
    "test": "jest --runInBand --detectOpenHandles --watchAll"
  }

--runInBand : 현재 프로세스에서 모든 테스트를 순차적으로 실행

--detectOpenHandles : express는 이벤트가 계속 열려 있기 때문에 열려 있는 리소스를 모두 닫아주는 옵션 (성능 저하가 올 수 있다. -> 디버깅에만 사용)

--watchAll : 변경 사항이 있을 때 모든 테스트를 다시 실행

코드

(1)

const httpMocks = require('node-mocks-http');
const { User } = require('../../../databases/models');
const mockRegisterUser = require('../../../../test/mock/register-user.json');
const mockLoginUser = require('../../../../test/mock/login-user.json');
const { register, login, logout, list } = require('./auth.ctrl');

jest.mock('../../../databases/models');

let req = null;
let res = null;
let next = null;

beforeEach(() => {
  req = httpMocks.createRequest();
  res = httpMocks.createResponse();
  next = jest.fn();
});

httpMocks(node-mocks-http) : Request 객체와 Response 객체를 얻기 위해 사용

User : 본인이 정의한 DB 모델

mockRegisterUser, mockLoginUser : req.body에 사용할 객체

ex)

// login-user.json

{ 
  "email": "TDDemail",
  "password": "TDDpassword"
}

register, login, logout, list : 모듈화된 API

jest.mock() : 자동으로 모듈을 모킹

beforeEach() : 테스트 함수가 실행되기 전 매번 실행

afterEach() : 테스트 함수가 실행된 후 매번 실행

beforeAll() : 맨 처음 한번만 실행

afterAll() : 마지막 한번만 실행

jest.fn() : mock 함수 생성

ex)

const test = jest.fn();

test.mockReturnValue('hi');

test(); // 'hi'

(2)

describe('[POST] /login', () => {
    beforeEach(async () => {
      req.body = mockLoginUser;
      db.query = jest.fn();
      req.session = {};
    });
    describe('[Success]', () => {
      it('function', () => {
        expect(typeof login).toBe('function');
      });
      it('request body', async () => {
        await login(req, res, next);
        expect(User.findOne).toBeCalledWith({
          where: mockLoginUser,
        });
      });
      it('return 201', async () => {
        User.findOne.mockResolvedValue('test');
        db.query.mockResolvedValue([]);
        await login(req, res, next);
        expect(res.statusCode).toBe(201);
        expect(res._isEndCalled()).toBe(true);
      });
    });
    describe('[Failure]', () => {
      it('return 401 Not found user', async () => {
        User.findOne.mockResolvedValue(null);
        await login(req, res, next);
        expect(res.statusCode).toBe(401);
        expect(res._isEndCalled()).toBe(true);
      });
      it('return 403 already login', async () => {
        User.findOne.mockResolvedValue('test');
        db.query.mockResolvedValue(['test']);
        await login(req, res, next);
        expect(res.statusCode).toBe(403);
        expect(res._isEndCalled()).toBe(true);
      });
      it('return 400 empty email', async () => {
        req.body.email = null;
        await login(req, res, next);
        expect(res.statusCode).toBe(400);
        expect(res._isEndCalled()).toBe(true);
      });
      it('return 400 empty password', async () => {
        req.body.password = null;
        await login(req, res, next);
        expect(res.statusCode).toBe(400);
        expect(res._isEndCalled()).toBe(true);
      });
    });
  });

describe : 테스트 코드를 그룹화

it(test) : 테스트할 코드

expect : 특정 조건을 충족하는지 테스트

toBe : 값이 일치하는지

toBeCalledWith : 특정 함수가 특정 인자 값과 함께 호출되었는지

mockResolvedValue : 비동기 테스트에서 비동기 함수를 모방

ex)

test('async test', async () => {
  const asyncMock = jest.fn().mockResolvedValue(43);

  await asyncMock(); // 43
});

_isEndCalled() : 결괏값이 잘 전달되는지 테스트

profile
Software Developer

0개의 댓글