
테스트를 작성하다보면 테스트 전후에 해줘야될 작업들이 생김.
→ 이런 처리 가능 하도록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.jsconst 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을 사용한 테스트는 건너뛰고 실행되어 제외됨)

참고