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

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

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

Repeating Setup

If you have some work you need to do repeatedly for many tests, you can use beforeEach and afterEach hooks.

Наприклад, припустимо, що кілька тестів взаємодіє з базою даних міст. У вас є метод 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 provides beforeAll and afterAll hooks to handle this situation.

For example, if both initializeCityDatabase() and clearCityDatabase() returned promises, and the city database could be reused between tests, we could change our test code to:

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();
});

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

За замовчуванням beforeAll і afterAll блоки застосувуються до кожного тесту у файлі. Ви також можете групувати тести використовуючи блок describe. Блоки коду beforeAll і afterAll, написані всередині блоку 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

Order of Execution

Jest виконує всі обробники блоків describe у файлі з тестами перед тим, як виконати будь-який тест. 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.

Розглянемо наступний тест файл та його вивід:

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

Just like the describe and test blocks Jest calls the before* and after* hooks in the order of declaration. Note that the after* hooks of the enclosing scope are called first. For example, here is how you can set up and tear down resources which depend on each other:

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

If you are using jasmine2 test runner, take into account that it calls the after* hooks in the reverse order of declaration. To have identical output, the above example should be altered like this:

  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, в якому логуються дані.