테스트를 작성하다보면 테스트 전후에 해줘야될 작업들이 생김.
→ 이런 처리 가능 하도록Jest
는help
함수 제공
npm test
timeout
(milliseconds
) 사용 가능기본 timeout
: 5초
→ 해당: beforeEach
/All
, afterEach
/All
, only
각 테스트 실행 직전, 초기화 해주는 과정이 필요 할 때
변수
num
을 만들고 0을 넣어줌. 그리고add
함수 테스트.
add
함수 (fn.js
)const fn = {
add: (num1, num2) => num1 + num2,
(...생략)
};
module.exports = fn;
fn.test.js
)성공
const fn = require("./fn");
let num = 0; // 👈
test("0 더하기 1은 1이야", () => {
num = fn.add(num, 1); // 👈
expect(num).toBe(1);
});
fn.test.js
const fn = require("./fn");
let num = 0;
test("0 더하기 1은 1이야", () => {
num = fn.add(num, 1); // 👈 num = 1
expect(num).toBe(1);
});
test("0 더하기 2은 2이야", () => {
num = fn.add(num, 2); // 👈 num = 3
expect(num).toBe(2);
});
test("0 더하기 3은 3이야", () => {
num = fn.add(num, 3); // 👈 num = 6
expect(num).toBe(3);
});
test("0 더하기 4은 4이야", () => {
num = fn.add(num, 4); // 👈 num = 10
expect(num).toBe(4);
});
테스트 결과
첫 번째: 성공. 나머지: 실패.
원인
num
에 계속 새로운 값이 할당됨.
num
(받은 값)이 0으로 시작해서 두번째 테스트부터 3, 6, 10
터미널
해결 방법
각 테스트 실행 직전, num
을 초기화 해주는 과정이 필요 → beforeEach
활용
이 파일의 각 테스트가 실행되기 전에 함수를 실행
유용한 경우
많은 테스트에서 사용될 global state
를 reset
하려는 경우
describe
블록 내부에 있을 경우
describe
블록의 각 테스트에 대해 실행됨.
일부 설정 코드를 한 번만 실행해야 하는 경우
테스트가 실행되기 전에 beforeAll
을 대신 사용할 것.
함수가 promise
를 반환하거나 generator
인 경우
Jest
는 test를 실행하기 전에 해당 promise
가 resolve
될 때까지 기다림.
beforeEach
활용 (num
을 0으로)
테스트 (fn.test.js
)
const fn = require("./fn");
let num = 0;
beforeEach(() => { // 👈 문제 해결
num = 0;
});
test("0 더하기 1은 1이야", () => {
num = fn.add(num, 1);
expect(num).toBe(1);
});
(...생략 (test 2, 3, 4))
테스트 결과
모두 통과
초기값 바꾸기 가능
테스트 (fn.test.js
)
const fn = require("./fn");
let num = 10; // 👈 초기값 10으로 수정
beforeEach(() => {
num = 0;
});
test("0 더하기 1은 1이야", () => {
num = fn.add(num, 1);
expect(num).toBe(1);
});
(...생략 (test 2, 3, 4))
테스트 결과
모두 통과
통과 이유
첫 번째 테스트 실행 전, 0으로 할당되기 때문
이 파일의 각 테스트가 완료된 후 함수를 실행
유용한 경우
각 테스트에서 생성된 임시 state
를 정리하려는 경우
describe
블록 내부에 있을 경우
describe
블록 내부에 있는 테스트 후에만 실행
모든 테스트가 실행된 후, 일부 정리를 한 번만 실행 하려면
afterAll
을 대신 사용
함수가 promise
를 반환하거나 generator
인 경우
Jest
는 계속하기 전에 해당 promise
가 resolve
될 때까지 기다림.
fn.test.js
)const fn = require("./fn");
let num = 10;
afterEach(() => { // 👈
num = 0;
});
test("0 더하기 1은 1이야", () => {
num = fn.add(num, 1);
expect(num).toBe(1);
});
(...생략 (test 2, 3, 4))
첫 번째 test case만 불통
0으로 바뀌는 타이밍은 첫 번째 테스트 이후 → 첫 번째 테스트는 불통 나머지 테스트는 각 테스트가 끝날 때마다 0으로 바뀜 → 통과초기 값이 10이기 때문
최초, 최후 각각 한 번씩 테스트 하는 것이 나은 경우
예를 들어테스트 수가 늘어날 수록 테스트 소요 시간도 증가함.
fn.js
)const fn = {
(...생략)
connectUserDb: () => { // 👈 userDb에 접속을 해서
return new Promise((res) => {
setTimeout(() => {
res({ // 👈 user 정보를 가져옴.
name: "Mike",
age: 30,
gender: "male",
});
}, 500); // 👈 0.5초 정도 걸리게 함.
});
},
disconnectDb: () => { // 👈 DB 연결 끊기
return new Promise((res) => {
setTimeout(() => {
res();
}, 500); // 👈 0.5초 정도 걸리게 함.
});
},
};
module.exports = fn;
fn.test.js
)const fn = require("./fn");
let user;
beforeEach(async () => { // 👈 작업 전, DB에 접속해서 user 데이터 가져옴.
user = await fn.connectUserDb();
});
afterEach(() => { // 👈 작업 후, DB connection 끊음.
return fn.disconnectDb();
});
// 👆 위의 각 작업은 0.5초가 걸림
test("이름은 Mike", () => { // 👈 테스트
expect(user.name).toBe("Mike");
});
즉, 이 테스트에 1초가 소요되는 것소요 시간: 1초가 넘음
fn.test.js
const fn = require("./fn");
let user;
beforeEach(async () => {
user = await fn.connectUserDb();
});
afterEach(() => {
return fn.disconnectDb();
});
test("이름은 Mike", () => {
expect(user.name).toBe("Mike");
});
test("나이는 30", () => { // 👈 테스트 추가
expect(user.age).toBe(30);
});
test("성별은 남성", () => { // 👈 테스트 추가
expect(user.gender).toBe("male");
});
테스트 결과
테스트 시간: 4초
4초 걸린 이유: 각 테스트 전후에 1초 (0.5초 + 0.5초)가 소요 되기 때문
문제점
이런 방식으로 test case가 늘어나면 안됨.
해결
사실 DB는 한 번만 연결해서 user 정보를 가지고 오고 모든 테스트를 마친 후에 끊어도 상관 없음. 최초, 최후에 각각 한 번씩 해주는 게 더 나음.
user 정보는 한 번만 가져오고 재활용하면 됨.
이 때 사용할 수 있는 것이 beforeAll
, afterAll
test 전체 실행 전 / 후 (각 테스트 케이스마다 실행되는 것이 아님)
유용한 경우
많은 테스트에서 사용할 global state
를 설정(set up
)하려는 경우
describe
블록 내부에 있을 경우
describe
블록의 시작 부분에서 실행
모든 테스트 전 마다 무언가 실행 하려면
beforeEach
사용하라.
함수가 promise
를 반환하거나 generator
인 경우
Jest
는 test를 실행하기 전에 해당 promise
가 resolve
될 때까지 기다림.
fn.test.js
(...생략)
beforeAll(async () => { // 👈 수정
user = await fn.connectUserDb();
});
afterAll(() => { // 👈 수정
return fn.disconnectDb();
});
(...생략)
전체 테스트 전후로 약 1초만 추가적으로 소요됨소요 시간: 1.9초 (훨씬 짧아짐)
비슷한 기능끼리 묶을 수 있음. (여러 관련 테스트를 그룹화하는 블록을 생성)
describe
내부의 before
와 after
describe
내부에서만 동작
carDb 함수 제작(fn.js
)
const fn = {
(...생략)
connectCarDb: () => {
return new Promise((res) => {
setTimeout(() => {
res({
brand: "bmw",
name: "z4",
color: "red",
});
}, 500);
});
},
disconnectCarDb: () => {
return new Promise((res) => {
setTimeout(() => {
res();
}, 500);
});
},
};
module.exports = fn;
비슷한 기능 끼리 묶기 (fn.test.js
)
describe
밖과 동일하게 작성함.
const fn = require("./fn");
(...생략)
// 👇 비슷한 기능(자동차 관련 작업) 끼리 묶음
describe("Car 관련 작업", () => { // 👈 설명 작성
let car;
beforeAll(async () => {
car = await fn.connectCarDb();
});
afterAll(() => {
return fn.disconnectCarDb();
});
test("이름은 z4", () => {
expect(car.name).toBe("z4");
});
test("브랜드는 bmw", () => {
expect(car.brand).toBe("bmw");
});
test("색상은 red", () => {
expect(car.color).toBe("red");
});
});
테스트 결과
설명과 depth로 구분 됨
describe
외부와 내부로 나눔.- 외/내부에 각각
test
,beforeEach
,beforeAll
,afterEach
,afterAll
가 있음.
밖 beforeEach
/ afterEach
는 이 페이지에 있는 모든 test
실행 전 / 후에 항상 실행
➕ 밖 beforeEach
: 내부beforeEach
보다 항상 먼저 실행 ⭐️
➕ 밖 afterEach
: 내부 afterEach
가 끝난 후 실행 ⭐️
밖 beforeEach
→안 beforeEach
→test
→안 afterEach
→밖 afterEach
const fn = require("./fn");
beforeAll(() => console.log("밖 beforeAll")); // 1
beforeEach(() => console.log("밖 beforeEach")); // 2, 6
afterEach(() => console.log("밖 afterEach")); // 4, 10
afterAll(() => console.log("밖 afterAll")); // 마지막
test("0 + 1 = 1", () => {
console.log("밖 test");
expect(fn.add(0, 1)).toBe(1); // 3
});
describe("Car 관련 작업", () => {
beforeAll(() => console.log("안 beforeAll")); // 5
beforeEach(() => console.log("안 beforeEach")); // 7
afterEach(() => console.log("안 afterEach")); // 9
afterAll(() => console.log("안 afterAll")); // 마지막 -1
test("0 + 1 = 1", () => {
console.log("안 test");
expect(fn.add(0, 1)).toBe(1); // 8
});
});
(...생략)
밖 beforeAll
밖 beforeEach
밖 test
밖 afterEach
안 beforeAll
밖 beforeEach
안 beforeEach
안 test
안 afterEach
밖 afterEach
안 afterAll
밖 afterAll
PASS ./fn.test.js
✓ 0 + 1 = 1 (4 ms)
Car 관련 작업
✓ 0 + 1 = 1 (2 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 0.136 s, estimated 1 s
Ran all test suites.
describe
밖밖에 있는 beforeAll
/ afterAll
은 처음과 마지막에 실행.
밖에 있는 test
진행
이 test
전 후로 밖에 있는 beforeEach
/ afterEach
실행
describe
내부밖에 있는 test
가 끝났으니까 내부로 진입
안에 있는 beforeAll
/ afterAll
이 각각 처음과 끝에 실행
안에 있는 test
가 실행이 될 텐데, 이 test
전후로 beforeEach
와 afterEach
가 실행이 되는데, ⭐️ 그 전에 밖에 beforeEach
가 먼저 실행이 됨
끝나고 나서는 밖에 있는 afterEach
가 실행됨. ⭐️
사용하는 경우
[단독 실행]
.only
가 붙여진test
케이스만 실행
큰 테스트 파일을 디버깅할 때, 테스트의 하위 집합만 실행 하고 싶은 경우가 있을 것이다. .only
를 사용하여 해당 테스트 파일에서 실행하고 싶은 테스트 지정 가능
사용 후 제거
디버깅에 사용하고 손상된 테스트를 수정한 후에는 제거
별칭
it.only(name, fn, timeout)
fit(name, fn, timeout)
외부의 어떤 요인 때문인지 or 코드 자체에 문제가 있는 건지 우선 파악하려는 경우
fn.test.js
const fn = require("./fn");
let num = 0;
test("0 더하기 1은 1", () => {
expect(fn.add(num, 1)).toBe(1);
});
test("0 더하기 2은 2", () => {
expect(fn.add(num, 2)).toBe(2);
});
test("0 더하기 3은 3", () => {
expect(fn.add(num, 3)).toBe(3);
});
test("0 더하기 4은 4", () => {
expect(fn.add(num, 4)).toBe(4);
num = 10; // 👈 num의 값을 바꿔줌
});
test("0 더하기 5은 5", () => {
expect(fn.add(num, 5)).toBe(6); // 👈 실패하도록 제작
});
마지막 테스트만 실패
이럴 때는 마지막 테스트만 한 번 더 실행해보는 것이 좋음.
외부의 어떤 요인 때문인지 or 코드 자체의 문제인지 우선 파악
fn.test.js
(...생략)
test.only("0 더하기 5은 5", () => { // 👈
(...생략)
});
테스트 결과
이 코드만 실행했는데도 실패 → 코드 자체에 문제 有
해당 코드만 실행. 나머지 케이스들 모두 skip.
불통 이유: 5여야 되는데 6 나옴
fn.test.js
(...생략)
test.only("0 더하기 5은 5", () => {
expect(fn.add(num, 5)).toBe(5); // 👈 5로 수정
});
통과 → 이제 이 코드 자체에 문제 없다는 증거
실패 → 실패한 test 케이스 코드에 대한 문제 없었기에 다른 외부 요인 찾아야 함.
fn.test.js
const fn = require("./fn");
let num = 0;
(...생략)
test("0 더하기 4은 4", () => {
expect(fn.add(num, 4)).toBe(4);
num = 10; // 👈 [문제] num 값이 바뀜.
});
(...생략)
이렇게 단순한 코드가 아니라, 당장 이 코드를 고치기 힘들다고 가정하면 우선 통과 시키기 위해서 이 부분을 건너뛰면 됨.
skip
, 주석 처리사용하는 경우
[제외] 건너뛸 테스트를 지정
큰 코드 베이스를 유지 관리할 때 어떤 이유로 일시적으로 broken된 테스트를 발견할 수 있다. 이 테스트 실행을 건너뛰고 싶지만 이 코드를 삭제하고 싶지 않다면 test.skip
을 사용하여 건너뛸 테스트 지정 가능
당장 코드를 고치기 힘들 때, 우선 통과 시키기 위해 해당 부분을 건너뛰기
주석 처리보다 나은 점
들여쓰기 및 구문 강조 표시를 유지
별칭
it.skip(name, fn)
xit(name, fn)
xtest(name, fn)
test.only
예시 5 이후
fn.test.js
)(...생략)
test.skip("0 더하기 4은 4", () => { // 👈 skip 사용
(...생략)
});
(...생략)
모두 성공 (
skip
을 사용한 테스트는 건너뛰고 실행되어 제외됨)
참고