Jest는 Meta에서 유지 관리하는 JavaScript 테스트 라이브러리로 Node 진영에서도 많이 사용하고 있다.
Weekly Downloads가 무려 20,679,279...
# devDependencies
npm install -D jest
"scripts": {
"test": "jest --runInBand --detectOpenHandles --watchAll"
}
--runInBand
: 현재 프로세스에서 모든 테스트를 순차적으로 실행
--detectOpenHandles
: express는 이벤트가 계속 열려 있기 때문에 열려 있는 리소스를 모두 닫아주는 옵션 (성능 저하가 올 수 있다. -> 디버깅에만 사용)
--watchAll
: 변경 사항이 있을 때 모든 테스트를 다시 실행
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'
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()
: 결괏값이 잘 전달되는지 테스트