Aller au contenu principal
Version : Suivant

Préparation et nettoyage

Souvent, lorsque vous écrivez des tests, vous devez effectuer un travail de préparation avant l'exécution des tests, et un travail de nettoyage après l'exécution des tests. Jest fournit des fonctions d'aide pour gérer cela.

Préparations répétées

Si vous avez un travail à faire de manière répétitive pour de nombreux tests, vous pouvez utiliser les hooks beforeEach et afterEach.

Par exemple, disons que plusieurs tests interagissent avec une base de données de villes. Vous avez une méthode initializeCityDatabase() qui doit être appelée avant chacun de ces tests, et une méthode clearCityDatabase() qui doit être appelée après chacun de ces tests. Vous pouvez le faire avec :

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

afterEach(() => {
clearCityDatabase();
});

test('la base de donnée possède Vienne', () => {
expect(isCity('Vienne')).toBeTruthy();
});

test('la base de donnée possède San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});

beforeEach et afterEach peuvent gérer le code asynchrone de la même manière que les tests peuvent gérer le code asynchrone - ils peuvent soit prendre un paramètre done, soit retourner une promesse. Par exemple, si initializeCityDatabase() renvoyait une promesse qui résolvait le moment où la base de données était initialisée, nous voudrions renvoyer cette promesse :

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

Préparation à usage unique

Dans certains cas, vous n'avez besoin de faire la préparation qu'une seule fois, au début d'un fichier. Cela peut être particulièrement gênant lorsque la préparation est asynchrone, et que vous ne pouvez donc pas le faire en même temps. Jest fournit les hooks beforeAll et afterAll pour gérer cette situation.

Par exemple, si les deux initializeCityDatabase() et clearCityDatabase() retournent des promesses, et que la base de données de la ville peut être réutilisée entre les tests, nous pourrions modifier notre code de test en :

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

afterAll(() => {
return clearCityDatabase();
});

test('la base de donnée possède Vienne', () => {
expect(isCity('Vienna')).toBeTruthy();
});

test('la base de donnée possède San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});

Champ d'application

Les hooks de premier niveau before* et after* s'appliquent à chaque test dans un fichier. Les crochets déclarés à l'intérieur d'un bloc describe ne s'appliquent qu'aux tests contenus dans ce bloc describe.

Par exemple, supposons que nous ayons non seulement une base de données sur les villes, mais aussi une base de données sur les aliments. Nous pourrions faire différentes configurations pour différents tests :

// S'applique à tous les tests de ce fichier
beforeEach(() => {
return initializeCityDatabase();
});

test('la base de donnée possède Vienne', () => {
expect(isCity('Vienne')).toBeTruthy();
});

test('la base de donnée possède San Juan', () => {
expect(isCity('San Juan')).toBeTruthy();
});

describe('correspondance entre les villes et les aliments', () => {
// S'applique uniquement aux tests de ce bloc describe
beforeEach(() => {
return initializeFoodDatabase();
});

test('Vienna <3 veau', () => {
expect(isValidCityFoodPair('Vienna', 'Wiener Schnitzel')).toBe(true);
});

test('San Juan <3 bananes plantain', () => {
expect(isValidCityFoodPair('San Juan', 'Mofongo')).toBe(true);
});
});

Notez que le beforeEach en haut du fichier est exécuté avant le beforeEach à l'intérieur du bloc describe. Il peut être utile d'illustrer l'ordre d'exécution de tous les 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

Ordre d'exécution

Jest exécute tous les gestionnaires de describe dans un fichier de test avant qu'il n'exécute les tests proprement dits. C'est une autre raison de faire la préparation et le nettoyage à l'intérieur des gestionnaires before* et after* plutôt qu'à l'intérieur des blocs describe. Une fois les blocs describe terminés, par défaut, Jest exécute tous les tests en série dans l'ordre où ils ont été rencontrés dans la phase de collecte, en attendant que chacun d'eux se termine et soit nettoyé avant de passer à la suite.

Considérez le fichier de test illustratif suivant et la sortie :

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

Tout comme les blocs describe et test, Jest appelle les hooks before* et after* dans l'ordre de déclaration. Veuillez noter que les crochets after* de la portée englobante sont appelés en premier. Par exemple, voici comment vous pouvez préparer et nettoyer des ressources qui dépendent les unes des autres :

beforeEach(() => console.log('préparation de la connexion'));
beforeEach(() => console.log('préparation de la base de données'));

afterEach(() => console.log('nettoyage de la base de données'));
afterEach(() => console.log('nettoyage de la connexion'));

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

describe('extra', () => {
beforeEach(() => console.log('préparation supplémentaire de la base de données'));
afterEach(() => console.log('nettoyage supplémentaire de la base de données'));

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

// préparation de la connexion
// préparation de la base de données
// test 1
// nettoyage de la base de données
// nettoyage de la connexion

// préparation de la connexion
// préparation de la base de données
// préparation supplémentaire de la base de données
// test 2
// nettoyage supplémentaire de la base de données
// nettoyage de la base de données
// nettoyage de la connexion
remarque

Si vous utilisez l'exécuteur de test jasmine2, tenez compte du fait qu'il appelle les hooks after* dans l'ordre inverse de la déclaration. Pour obtenir un résultat identique, l'exemple ci-dessus doit être modifié comme suit :

  beforeEach(() => console.log('préparation de la connexion'));
+ afterEach(() => console.log('nettoyage de la connexion'));

beforeEach(() => console.log('préparation de la base de données'));
+ afterEach(() => console.log('nettoyage de la base de données'));

- afterEach(() => console.log('nettoyage de la base de données'));
- afterEach(() => console.log('nettoyage de la connexion'));

// ...

Indications générales

Si un test échoue, l'une des premières choses à vérifier : est-ce que le test échoue si c'est le seul test exécuté ? Pour exécuter un seul test avec Jest, changez temporairement cette commande test en une commande test.only :

test.only('ce sera le seul test exécuté', () => {
expect(true).toBe(false);
});

test('ce test ne s'exécutera pas', () => {
expect('A').toBe('A');
});

Si vous avez un test qui échoue souvent lorsqu'il est exécuté dans une série plus grande, mais qui n'échoue pas lorsque vous l'exécutez seul, il est fort probable que quelque chose d'un autre test interfère avec celui-ci. Vous pouvez souvent corriger cela en nettoyant certains états partagés avec beforeEach. Si vous n'êtes pas sûr qu'un état partagé soit modifié, vous pouvez également essayer un beforeEach qui journalise les données.