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