setup and teardown

정민교·2023년 7월 16일
0

jest

목록 보기
4/5

📒

jest는 테스트 실행 전에 설정 작업이 필요하거나 테스트 실행 후에 정리 작업이 필요한 경우를 처리하기 위한 헬퍼 함수를 제공한다.

✔️Repeatin Setup

📌beforeEach, afterEach

테스트마다 반복해야하는 작업이 있다면 beforeEachafterEach를 사용할 수 있다.

beforeEachafterEach는 각 테스트 전, 그리고 각 테스트 후 반복해서 실행된다.

예를 들어, 여러 테스트가 도시 데이터베이스와 상호작용한다고 가정하자.

이러한 테스트 각각에서 호출해야하는 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();
});

beforeEachafterEach도 비동기 코드를 처리할 수 있다. 즉, done매개변수를 사용하거나 프로미스를 반환할 수 있다.

beforeEach(() => {
  return initializeCityDatabase();
});

✔️One-Time Setup

테스트마다 반복해야 할 필요 없이 한 번만 실행되면 되는 설정의 경우에는 beforeAllafterAll를 사용할 수 있다.

예를 들어, 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();
});

✔️Scope

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

✔️Order of Execution

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

이로 인해 다음과 같은 이점이 있다.

  1. 테스트 실행 순서를 예측 가능하게 만든다. 이는 테스트 결과의 일관성 및 유지 관리를 쉽게 해준다.
  2. 테스트 환경은 각 테스트 간에 격리되며 중복이 제거된다. 이는 각 테스트가 다른 테스트의 상태에 영향을 받지 않도록 보장한다.
  3. 모든 describe 블록이 완료된 후에 테스트를 실행하므로, 필요한 경우 테스트를 동시에 실행하여 동시성을 개선할 수 있다.

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로 변경하여 모든 테스트가 실행되도록 해야한다.

이 방법은 개별 테스트를 신속하게 실행하고 디버깅하는 데 유용하다.

profile
백엔드 개발자

0개의 댓글