Setup and Teardown
Часто під час написання тестів є певна підотовча робота, яка повинна бути виконана перед запуском тестів а також певна фінальна робота, яка повинна бути виконана після запуску тестів. 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();
});
Одноразове налаштування
Інколи вам потрібно виконати налаштування перед тестами лише один раз на початку файла. This can be especially bothersome when the setup is asynchronous, so you can't do it inline. 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
. Коли тести знаходяться всередині блоку describe
, блоки before
і after
застосовуються лише до тестів всередині цього describe
.
For example, let's say we had not just a city database, but also a food database. We could do different setup for different tests:
// 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 sausage', () => {
expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
});
test('San Juan <3 plantains', () => {
expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
});
});
Note that the top-level beforeEach
is executed before the beforeEach
inside the describe
block. It may help to illustrate the order of execution of all hooks.
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 of describe and test blocks
Jest executes all describe handlers in a test file before it executes any of the actual tests. This is another reason to do setup and teardown inside before*
and after*
handlers rather than inside the describe blocks. Once the describe blocks are complete, by default Jest runs all the tests serially in the order they were encountered in the collection phase, waiting for each to finish and be tidied up before moving on.
Consider the following illustrative test file and output:
describe('outer', () => {
console.log('describe outer-a');
describe('describe inner 1', () => {
console.log('describe inner 1');
test('test 1', () => {
console.log('test for describe inner 1');
expect(true).toEqual(true);
});
});
console.log('describe outer-b');
test('test 1', () => {
console.log('test for describe outer');
expect(true).toEqual(true);
});
describe('describe inner 2', () => {
console.log('describe inner 2');
test('test for describe inner 2', () => {
console.log('test for describe inner 2');
expect(false).toEqual(false);
});
});
console.log('describe outer-c');
});
// describe outer-a
// describe inner 1
// describe outer-b
// describe inner 2
// describe outer-c
// test for describe inner 1
// test for describe outer
// test for describe inner 2
Загальні поради
Якщо тест падає, одна з перших речей, яку варто перевірити - це чи падає цей тест, якщо запускається лише він. To run only one test with Jest, temporarily change that test
command to a 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
. If you're not sure whether some shared state is being modified, you can also try a beforeEach
that logs data.