-
2019-10-14 개발일지개발일지 2019. 10. 14. 11:37
오늘은 마이그레이션 프로젝트를 잠시 멈추고 이전부터 해보고 싶었던 JEST 테스트 라이브러리 프레임워크를 공부해봤다.
자바 스프링 진영의 경우는 jUnit이 있는데, 백기선님이 인프런 강좌에서 사용하시는 걸 보면서 '해봐야지' 하다가 신입일 때 프로젝트 기간 쳐내고 하느라 테스트까지 공부하고 할 여력이 없었다...(응 핑계ㄴㄴ)
이번에 JEST 문법을 보면서 jUnit하고 크게 다른게 없어 보여서 프레임워크 하나만 깊게 숙지해놓으면 다른 테스트 프레임워크도 쉽게 접근할 수 있을 것 같다고 생각이 들었다.
설치 및 환경 설정을 해보자.
JEST 설치
npm 패키지 중 jest를 설치한다. JEST를 프로젝트에 설치하자.
나의 경우엔 이미 프로젝트가 이미 진행 중이었는데, 문제없이 테스트 환경을 만들 수가 있었다.
@types/jest도 설치하자. 이후 @types/jest도 설치했다.
JEST 테스트 작성 및 실행
package.json을 열어서 test 스크립트를 jest로 변경한다. 프로젝트 내의 package.json을 열고 test 스크립트 내용을 "jest" 실행 명령어로 변경한다.
프로젝트에 대강 test 폴더를 만들고 test.ts 파일을 만들자. jest 공식 문서에서는 js를 기준으로 설명하지만 난 현재 TS를 사용하니까... 일단 ts확장자로 test.ts를 만들었다.
공식문서: https://jestjs.io/docs/en/getting-started
Jest · 🃏 Delightful JavaScript Testing
🃏 Delightful JavaScript Testing
jestjs.io
테스트 코드를 작성하자. test.ts에 테스트 코드를 작성하자.
1은 1이라는 것이 사실인지 테스트 코드를 작성해봤다.
터미널에서 npm test로 jest를 실행해보자. jest를 실행하면 test.ts 파일이 실행된다.
이후 test 단위 제목이 나타난다. (test()에 첫 인자로 넣은 문자열이 테스트 코드의 제목이 된다.)
그리고 테스트에 대한 결과를 알려준다.
성공한 경우엔 위와 같이 결과를 레포트해주고,
실패한 경우 실패한 데이터 내용과 문제가 되는 테스트 코드 라인을 지적해준다. 실패가 발생하면 실패의 원인 내용과 테스트 코드의 어디에서 문제가 발생했는지 알려준다.
(현재는 어떤 원리로 테스트 코드 파일을 찾는지 모르겠다. 좀 더 공부해야한다.)* JEST는 파일 명에 'test.'나 'spec.'이란 문자열이 들어간 파일을 찾는다. 이러한 설정은 추후에 바꿀 수도 있는 것 같다.
jest.config.js를 열어보면 위와 같이 test 파일을 찾기 위한 설정을 할 수가 있다. JEST 기본 구성
jest --init 구문을 실행한다. 이제 JEST 테스트 프레임워크의 프로젝트 기본 구성 파일을 생성하자.
명령줄에 jest --init을 통해 jest.config.js 파일을 생성할 수 있다.
babel-jest, @babel/core, @babel/preset-env를 설치하자. 만약 프로젝트에 바벨을 적용할 생각이라면 바벨 코어와 프리셋을 설치하고 환경을 설정하자.
생성된 babel.config.js를 열고 프리셋 설정을 추가해주자. 설치한 프리셋을 적용해봤다.
사실 바벨에 대해서는 자세하게 알지 못해서 추후 바벨 도큐먼트를 읽어봐야할 것 같다.
Babel · The compiler for next generation JavaScript
The compiler for next generation JavaScript
babeljs.io
JEST TS 환경 구성
@babel/preset-typescript 를 다운로드받는다. TS 환경의 JEST 구성을 해보자.
@babel/preset-typescript를 설치한다.
babel.config.js에 프리셋 설정을 추가하자. 설치한 프리셋을 babel.config.js를 열어서 추가해주면 끝이다.
* Babel7 프리셋 설정 방식은 타입스크립트 코드를 바벨로 JS로 변환한 후 검증하는 방식이다.
따라서 위의 방식으로 JEST를 설정하면 TS의 타입 체크 기능은 수행되지가 않는다.
(쉽게 얘기해서 TS를 TS로 읽지 않고 TS 컴파일러로 JS로 컴파일 하듯 JS로 바벨 변환을 한 후에 코드를 읽는다는 것이다.)
만약 TS의 타입 체크와 같은 TS만의 장점을 적용하여 테스트를 진행하고 싶다면 ts-jest를 알아보자.
(난 이제 jest의 Getting Started를 읽고 있으니 ts-jest는 추후에 추가로 공부할 것이다.)ts-jest: https://github.com/kulshekhar/ts-jest
kulshekhar/ts-jest
TypeScript preprocessor with sourcemap support for Jest - kulshekhar/ts-jest
github.com
어차피 ts-jest를 사용해야하더라.
안그러면 babel로 변환한 테스트만을 해야하는데 요거 해야할 게 너무 많음...
TS에서 시퀄라이즈 모델링 기능 때문에 사용하는 ES7의 데코레이션 기능을 js로 변환하여 사용하려면 babel.config에 설정해줘야하고 이런 번거로움들이 귀찮아서 그냥 ts-jest 설치하고 실제 서버 리스닝 테스트 및 통신 테스트를 진행해봤다.
코드 작성전에 다음과 같은 모듈을 개발 의존성(--save-dev | -D)에 추가하여 설치해주자.
- typescript
- ts-jest
- supertest
- @types/supertest
import expressConfig from '../config/express_config'; import { WebSequelize } from '../config/sequelize'; const app = expressConfig(); const webSequelize = new WebSequelize(); webSequelize.connectTest(); app.listen(5050, () => { console.log('app listening on port 5050 / jindo7-node project'); }); export default app;
서버를 리스닝하는 파일에서 서버를 모듈로 내보내기를 설정했다.
이는 test코드에서 해당 app 객체를 받아서 실제 리스닝을 실행하고 라우트 통신을 테스트하기 위해서 작업해야 했다.
import supertest from 'supertest'; import app = require('../../../src/app'); test('app route test', async () => { const response = await supertest(app.default).get( '/api/board/list/notice/0' ); expect(response.status).toBe(200); });
라우트 통신을 위해 supertest 모듈을 추가해야 했다.
그리고 라우트는 app의 라우트를 사용해야한다.
요렇게 라우트 통신을 진행할 수 있었다.
그런데 '테스트는 deterministic 해야한다.' 는 내용을 읽었다. (언제 실행되든 항상 같은 결과를 도출해야 한다는 원칙이 있나봄)
단위 테스트가 외부 환경에 의존하기 때문에 문제가 된다는 건데 (서버가 가동이 되어야한다는 의미), 서버가 실행이 가능하든 불가능하든 테스트 코드는 수행이 되어야 한다는 의미다.
예를 들어서 내가 새로운 기능의 API를 만들어야하는데, 해당 API를 테스트 코드를 작성했는데 반드시 서버가 실행되어야 테스트 코드가 실행이 되는 구조라면 여간 불편한게 아니다.
그래서 이런 문제들을 해결하기 위해 mocking(가짜, 흉내낸)개념이 필요해진다.
가짜로 함수를 만들고 가짜로 데이터를 만들어서 "비즈니스 로직이 돌아가는 가"에 집중하는 것이다.
할 거 왜이렇게 많냐 @-@
'개발일지' 카테고리의 다른 글
2019-10-16 개발일지 (0) 2019.10.16 2019-10-15 개발일지 (0) 2019.10.15 2019-10-11 개발일지 (0) 2019.10.11 2019-10-10 개발일지 (0) 2019.10.10 2019-10-08 개발일지 (0) 2019.10.08