✅ Jest란?
Jest는 페이스북에서 만들어서 React와 더불어 많은 자바스크립트 개발자로부터 좋은 반응을 얻고 있는 테스팅 라이브러리 입니다.
Jest는 라이브러리 하나만 설치하면, Test Runner와 Test Mathcher 그리고 Test Mock 프레임워크까지 제공해주기 때문에 현재 대세라고 말할 수 있습니다.
✅ Jest 학습 이유
많은 기업에서 Jest를 이용한 테스트를 진행한다는 것을 알게되었고 TDD를 사용해 개발을 진행해보고 싶었습니다.
TDD를 사용하게 될 경우 생산성이 저하될 수 있다는 단점이 있긴 하지만 버그가 줄어들고 소스코드가 간결해진다는 장점이 있습니다.
Test Code를 작성하여 정확성을 높이고 어떻게 하면 더 나은 코드를 작성할 수 있을지 고민하고 개선해보기 위해 공부하게 되었습니다.
✅ Jest 설치
> npm i -D jest
더보기
- install
-- jest 설치
npm install --save-dev jest
-- babel 관련 모듈 설치
npm install --save-dev babel-jest @babel/core @babel/preset-env @babel/preset-react
-- .ts,.tsx 파일을 트랜스파일 해주는 babel plugin
npm install --save-dev @babel/preset-typescript
- babel.config.js
module.exports = {
presets: [
["@babel/preset-env", { targets: { node: "current" } }],
"@babel/preset-typescript",
["@babel/preset-react", { runtime: "automatic" }],
],
};
- typeChecking 기능 관련 모듈 설치
- ts-jest 를 이용하여 typeChecking 기능을 사용하려면 jest configuration를 정의해주어야 한다.
npm install --save-dev ts-jest
- Jest 관련 Type 정의 모듈 설치
-- test 파일에서 사용되는 jest 관련 Type이 정의되어있다
npm install --save-dev @types/jest
-- 스냅샷 테스트를 도와주는 react-test-renderer
npm install --save-dev react-test-renderer
-- jest-environment-jsdom
npm install --save-dev jest-environment-jsdom
- Jest's configuration 정의하기
- React 에서 진행되는 Test 는 Node환경이 아닌 브라우저 환경에서도 Test 할 수 있어야 한다. 따라서 package.json 안에 jest:{} 필드를 삽입하거나, jest.config.js를 만들어서 테스트 환경을 Node로 할것인지 jsdom으로 할것인지 정의해야한다.
{
...
"devDependencies": {
...
},
"dependencies": {
...
},
"jest" : { // 이 부분
"testEnvironment": "jsdom" // Default : "node"
} //
}
- test scripts 정의
// package.json
{
"scripts" : {
"test": "jest --watchAll --verbose"
}
}
- @testing-library/react 설치
npm install --save-dev @testing-library/react
- download vscode "Jest" extension
✅ 기본 개념
기본 구조
sum.js
function sum(a, b) {
return a + b;
}
module.exports = sum; // 내보내기
sum.test.js
- test: 새로운 테스트 케이스 만드는 함수
- expect : 특정 값이 ~~일 것이다 사전에 정의 하고 통과하면 테스트 성공시키고 통과하지 않으면 테스트 실패시킴
- toBe : matchers라고 부르는 함수,
const sum = require('./sum');
test('1 + 2 = 3', () => {
expect(sum(1, 2)).toBe(3);
});
실행결과
$ npm test
> test
> jest
PASS ./sum.test.js
√ 1+2=3 (20 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.555 s
Ran all test suites.
test 대신 it
test대신 it라는 키워드를 사용하게 되면 테스트케이스 설명을 영어로 작성하게 되는 경우 "말이 되게" 작성할 수 있다.
한국어로 작성하는것도 가능하다
const sum = require('./sum')
// test('1+2=3', () => {
// expect(sum(1, 2)).toBe(3)
// })
it('calculates 1 + 2', () => {
expect(sum(1, 2)).toBe(3)
})
describe
여러개의 테스트케이스를 묶을수 있음
sum.js
function sum(a, b) {
return a + b
}
function sumOf(numbers) {
let result = 0
numbers.forEach(n => {
result += n
})
return result
}
// 각각 내보내기
exports.sum = sum
exports.sumOf = sumOf
sum.test.js
const {sum, sumOf} = require('./sum')
describe('sum', ()=> {
it('calc 1 + 2', () => {
expect(sum(1, 2)).toBe(3)
})
it('calc all numbers', () => {
let array = [1, 2, 3, 4, 5]
expect(sumOf(array)).toBe(15)
})
})
✅TDD
Test Driven Development : 테스트 주도 개발
- 선 테스트코드 작성 후 구현
실패
- 첫번째 절차
- 프로젝트의 전체 기능에 대해 처음부터 모든 테스트케이스를 만드는 것이 아니라, 지금 가장 먼저 구현할 기능 하나씩 테스트 케이스를 작성한다
- 상황에 따라서 한꺼번에 여러 테스트케이스를 먼저 작성하기도함
성공
- 우리가 작성하는 실패하는 테스트케이스를 통과시키기 위해 코드를 작성해 테스트 통과시키기
리팩토링
- 우리가 구현한 코드에 중복되는 코드가 있거나 더 개선시킬 방법이 있다면 리팩토링 진행
- 리팩토링 진행하고 나서도 TC가 성공하는지 확인
- 절차가 끝나면 다시 처음 절차로 돌아가서 실패하는 TC를 작성
장점
- 테스트 케이스를 작성할 때 주로 작은 단위로 만들기 때문에 코드 작성할 때 코드가 방대해지지 않고 코드의 모듈화가 자연스럽게 이루어면서 개발이 진행됨
- 테스트 커버리지가 높아짐 => 리팩토링도 쉬워지고 유지보수도 쉬워짐 => 프로젝트의 퀄리티가 높아짐
- 협업에도 도움이됨
- 버그에 낭비하는 시간도 최소한으로 할 수 있으며 구현한 기능이 요구사항을 충족하는지 쉽게 확인 가능
✅ 예시
stats.ts
// 최대값
export const max = (numbers: number[]): number => Math.max(...numbers)
// 최소값
export const min = (numbers: number[]): number => Math.min(...numbers)
// 평균값
export const avg = (numbers: number[]): number => {
return numbers.reduce((acc:number, cur: number, index: number, {length}) => acc + cur / length, 0)
}
// 정렬
export const sort = (numbers: number[]): number[] => {
return numbers.sort((a, b) => a - b)
}
// 중앙값
export const median = (numbers: number[]): number => {
const {length} = numbers
const middle = Math.floor(length / 2)
return length % 2 ? numbers[middle] : (numbers[middle - 1] + numbers[middle]) / 2
}
stats.test.js
const stats = require('./stats')
//test
describe('stats', () => {
it('최댓값 찾기', () => {
expect(stats.max([1, 2, 3, 4])).toBe(4);
})
it('최솟값 찾기', () => {
expect(stats.min([1, 2, 3, 4])).toBe(1)
})
it('평균값 찾기', () => {
expect(stats.avg([1, 2, 3, 4, 5])).toBe(3)
})
// toEqual : 객체 또는 배열을 비교할 때 사용
describe('median', () => {
it('정렬하기', () => {
expect(stats.sort([5, 4, 1, 2, 3])).toEqual([1, 2, 3, 4, 5])
})
it('홀수 길이의 중앙값', () => {
expect(stats.median([1, 2, 3, 4, 5])).toBe(3)
})
it('짝수 길이의 중앙값', () => {
expect(stats.median([1, 2, 3, 4, 5, 6])).toBe(3.5)
})
})
})