Перейти до основного змісту
Версія: 29.0

Підготовка та очистка

Часто під час написання тестів є певна підотовча робота, яка повинна бути виконана перед запуском тестів а також певна фінальна робота, яка повинна бути виконана після запуску тестів. Jest надає допоміжні функції, щоб впоратись з цим.

Повторення налаштувань

Якщо у вас певні задачі, які ви повинні виконувати щоразу для багатьох тестів, використовуйте хуки 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 або повертаючи проміс. Наприклад, якщо функція initializeCityDatabase() повертає проміс, який виконається, коли база даних буде ініціалізована, ми можемо повернути цей проміс:

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

Одноразове налаштування

Інколи вам потрібно виконати налаштування перед тестами лише один раз на початку файла. Це може бути проблемою, якщо це налаштування асинхронне і, відповідно, ви не можете виконати його інлайново. Jest надає хуки 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();
});

Обмеження контексту

Хуки верхнього рівня before* та after* застосовуються до кожного тесту в файлі. Зазначені хуки всередині блоку describe застосовуються тільки до тестів в межах цього блоку.

Наприклад, уявімо, що у нас є не тільки база даних міст, але і база даних їжі. Ми могли б виконати різні налаштування для різних тестів:

// Застосовується до всіх тестів у поточному файлі
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', () => {
// Застосовується тільки до тестів в поточному блоці desribe
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);
});
});

Зверніть увагу, що верхньорівневий beforeEach виконується перед beforeEach всередині блоку describe. Приклад нижче може допомогти проілюструвати порядок виконання всіх блоків.

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 у файлі з тестами перед тим, як виконати будь-який тест. Це ще одна причина налаштовувати тести та виконувати очистку всередині обробників before* та after*, а не всередині блоків describe. Після виконання всіх блоків 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* охоплюючого контексту викликаються першими. Наприклад, ви можете налаштувати та знести ресурси, які залежать один від одного:

beforeEach(() => console.log('connection setup'));
beforeEach(() => console.log('database setup'));

afterEach(() => console.log('database teardown'));
afterEach(() => console.log('connection teardown'));

test('test 1', () => console.log('test 1'));

describe('extra', () => {
beforeEach(() => console.log('extra database setup'));
afterEach(() => console.log('extra database teardown'));

test('test 2', () => console.log('test 2'));
});

// connection setup
// database setup
// test 1
// database teardown
// connection teardown

// connection setup
// database setup
// extra database setup
// test 2
// extra database teardown
// database teardown
// connection teardown
note

Якщо ви використовуєте виконавець тестів jasmine2, візьміть до уваги, що він викликає хуки after* у зворотному порядку декларації. Щоб мати однаковий вивід, наведений вище приклад повинен бути змінений наступним чином:

  beforeEach(() => console.log('connection setup'));
+ afterEach(() => console.log('connection teardown'));

beforeEach(() => console.log('database setup'));
+ afterEach(() => console.log('database teardown'));

- afterEach(() => console.log('database teardown'));
- afterEach(() => console.log('connection teardown'));

// ...

Загальні поради

Якщо тест падає, одна з перших речей, яку варто перевірити - це чи падає цей тест, якщо запускається лише він. Щоб запустити тільки один тест з допомогою Jest, тимчасово змініть виклик test на 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');
});

Якщо у вас є тест, який часто падає, коли він запускається з іншими тестами в наборі, але не падає, коли запущений лише він, велика ймовірність, що на нього впливає щось з інших тестів. Часто це можна виправити, очистивши спільний стан з допомогою beforeEach. Якщо ви не впевнені, чи змінюється якийсь спільний стан, можна також спробувати beforeEach, в якому логуються дані.