jest는 테스트 실행 전에 설정 작업이 필요하거나 테스트 실행 후에 정리 작업이 필요한 경우를 처리하기 위한 헬퍼 함수를 제공한다.
테스트마다 반복해야하는 작업이 있다면 beforeEach
랑 afterEach
를 사용할 수 있다.
beforeEach
와 afterEach
는 각 테스트 전, 그리고 각 테스트 후 반복해서 실행된다.
예를 들어, 여러 테스트가 도시 데이터베이스와 상호작용한다고 가정하자.
이러한 테스트 각각에서 호출해야하는 initializeCityDatabase() 메서드와 각 테스트 후에 호출해야하는 clearCityDatabase() 메서드가 있다면 이를 다음과 같이 작성할 수 있다.
beforeEach(() => {
initializeCityDatabase();
});
afterEach(() => {
clearCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
beforeEach
와 afterEach
도 비동기 코드를 처리할 수 있다. 즉, done매개변수를 사용하거나 프로미스를 반환할 수 있다.
beforeEach(() => {
return initializeCityDatabase();
});
테스트마다 반복해야 할 필요 없이 한 번만 실행되면 되는 설정의 경우에는 beforeAll
과 afterAll
를 사용할 수 있다.
예를 들어, initializeCityDatabase()와 clearCityDatabase() 둘 다 프로미스를 반환하고, 도시 데이터베이스가 테스트 간에 재사용될 수 있다면, 테스트 코드를 다음과 같이 변경할 수 있다.
beforeAll(() => {
return initializeCityDatabase(); // 프로미스 반환
});
afterAll(() => {
return clearCityDatabase(); // 프로미스 반환
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
describe 블록 내에 선언된 before
, after
훅은 해당 describe 블록 내의 테스트에만 적용된다.
// Applies to all tests in this file
beforeEach(() => {
return initializeCityDatabase();
});
test('city database has Vienna', () => {
expect(isCity('Vienna')).toBeTruthy();
});
test('city database has San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});
describe('matching cities to foods', () => {
// Applies only to tests in this describe block
beforeEach(() => {
return initializeFoodDatabase();
});
test('Vienna <3 veal', () => {
expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
});
test('San Juan <3 plantains', () => {
expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
});
});
describe 블록 내부의 beforeEach
보다 상위 레벨의 beforeEach
훅이 먼저 실행된다.
상위 레벨의 beforeEach
보다 describe 블록 내부의 beforeAll
훅이 더 우선된다.
beforeAll(() => console.log('1 - beforeAll'));
afterAll(() => console.log('1 - afterAll'));
beforeEach(() => console.log('1 - beforeEach'));
afterEach(() => console.log('1 - afterEach'));
test('', () => console.log('1 - test'));
describe('Scoped / Nested block', () => {
beforeAll(() => console.log('2 - beforeAll'));
afterAll(() => console.log('2 - afterAll'));
beforeEach(() => console.log('2 - beforeEach'));
afterEach(() => console.log('2 - afterEach'));
test('', () => console.log('2 - test'));
});
// 1 - beforeAll
// 1 - beforeEach
// 1 - test
// 1 - afterEach
// 2 - beforeAll
// 1 - beforeEach
// 2 - beforeEach
// 2 - test
// 2 - afterEach
// 1 - afterEach
// 2 - afterAll
// 1 - afterAll
Jest는 테스트 파일에서 실제 테스트를 실행하기 전에 모든 describe 핸들러를 먼저 실행한다.
이것이 describe 블록 내부가 아닌 before 및 after 핸들러 내에서 설정 및 정리 작업을 수행해야 하는 또 다른 이유다.
모든 describe 블록이 완료되면 기본적으로 Jest는 수집 단계에서 발견된 순서대로 모든 테스트를 직렬로 실행하며, 각 테스트가 끝나고 정리될 때까지 기다렸다가 계속 진행한다.
describe('describe outer', () => {
console.log('describe outer-a');
describe('describe inner 1', () => {
console.log('describe inner 1');
test('test 1', () => console.log('test 1'));
});
console.log('describe outer-b');
test('test 2', () => console.log('test 2'));
describe('describe inner 2', () => {
console.log('describe inner 2');
test('test 3', () => console.log('test 3'));
});
console.log('describe outer-c');
});
// describe outer-a
// describe inner 1
// describe outer-b
// describe inner 2
// describe outer-c
// test 1
// test 2
// test 3
이로 인해 다음과 같은 이점이 있다.
describe 및 test 블록과 마찬가지로 Jest는 선언된 순서대로 before 및 after 훅을 호출한다.
주의할 점은 주변 범위의 after* 훅이 먼저 호출된다는 것이다. 예를 들어, 서로에게 종속된 리소스의 설정 및 해제 방법은 다음과 같습니다:
describe('resources setup and teardown', () => {
beforeAll(() => console.log('A - beforeAll'));
afterAll(() => console.log('A - afterAll'));
beforeEach(() => console.log('A - beforeEach'));
afterEach(() => console.log('A - afterEach'));
test('test A', () => console.log('test A'));
describe('nested resources', () => {
beforeAll(() => console.log('B - beforeAll'));
afterAll(() => console.log('B - afterAll'));
beforeEach(() => console.log('B - beforeEach'));
afterEach(() => console.log('B - afterEach'));
test('test B', () => console.log('test B'));
});
});
// A - beforeAll
// A - beforeEach
// test A
// A - afterEach
// B - beforeAll
// A - beforeEach
// B - beforeEach
// test B
// B - afterEach
// A - afterEach
// B - afterAll
// A - afterAll
테스트가 실패하면 가장 먼저 확인해야 할 사항 중 하나는 해당 테스트가 유일한 테스트로 실행될 때 실패하는지 여부이다.
Jest로 한 개의 테스트만 실행하려면, 일시적으로 해당 테스트 명령어를 test.only로 변경하면 된다.
test.only('this will be the only test that runs', () => {
expect(true).toBe(false);
});
test('this test will not run', () => {
expect('A').toBe('A');
});
위의 예제에서 test.only를 사용하면, 첫 번째 테스트만 실행되고 두 번째 테스트는 실행되지 않는다.
이렇게 하면 특정 테스트가 독립적으로 실행될 때 실패 원인을 찾기 쉽게 해주며, 다른 테스트와의 상호 작용이 문제를 일으키는지 확인할 수 있다.
문제를 해결한 후에는 test.only를 다시 test로 변경하여 모든 테스트가 실행되도록 해야한다.
이 방법은 개별 테스트를 신속하게 실행하고 디버깅하는 데 유용하다.