Note du traducteur
C'est la traduction du fichier when-to-use-plan.md. Voici un lien vers les différences avec le master de AVA (Si en cliquant sur le lien, vous ne trouvez pas le fichier when-to-use-plan.md
parmi les fichiers modifiés, vous pouvez donc en déduire que la traduction est à jour).
Traductions : English, Español, Italiano, 日本語, Português, Русский, 简体中文
Une des différences principales entre AVA et tap
/tape
, c'est le comportement de t.plan()
. Dans AVA, t.plan()
est uniquement utilisé pour vérifier que le nombre assertions appelées correspond, il n'arrête pas automatiquement le test.
Beaucoup d'utilisateurs venant de tap
/tape
sont habitués à utiliser t.plan()
de manière prolifique dans chaque test. Cependant, dans AVA, nous ne considérons pas que cela soit une « bonne pratique ». Au lieu de cela, nous croyons que t.plan()
devait être utilisé seulement dans les situations où il fournit une certaine valeur.
t.plan()
est inutile dans la plupart des tests synchrones.
test('simple sums', t => {
// MAUVAIS : Il n'y a pas de débranchement ici - t.plan() est inutile
t.plan(2);
t.is(1 + 1, 2);
t.is(2 + 2, 4);
});
t.plan()
ne fournit aucune valeur ici, et crée une tâche supplémentaire si jamais vous décidez d'ajouter ou supprimer des assertions.
test('gives foo', t => {
t.plan(1);
return somePromise().then(result => {
t.is(result, 'foo');
});
});
A première vue, ce test semblent utiliser correctement t.plan()
car un gestionnaire de promesse asynchrone est implémenté. Cependant, il y a plusieurs problèmes avec ce test :
-
t.plan()
est sans doute utilisé ici pour se protéger contre la possibilité quesomePromise()
soit rejetée. Mais le retour d'une promesse rejetée fera échouer de toute façon le test. -
Il serait préférable de profiter de
async
/await
:
test('gives foo', async t => {
t.is(await somePromise(), 'foo');
});
test('rejects with foo', t => {
t.plan(2);
return shouldRejectWithFoo().catch(reason => {
t.is(reason.message, 'Hello');
t.is(reason.foo, 'bar');
});
});
Ici, l'utilisation de t.plan ()
vise à garantir que le code à l'intérieur du bloc catch
soit exécuté.
Au lieu de cela, vous devriez profiter de t.throwsAsync
et async
/await
, car cela conduit à rendre le code plus simple ce qui est plus facile à suivre :
test('rejects with foo', async t => {
const reason = await t.throwsAsync(shouldRejectWithFoo());
t.is(reason.message, 'Hello');
t.is(reason.foo, 'bar');
});
test('throws', t => {
t.plan(2);
try {
shouldThrow();
} catch (err) {
t.is(err.message, 'Hello');
t.is(err.foo, 'bar');
}
});
Comme indiqué dans l'exemple précédent, l'utilisation de l'assertion t.throws()
avec async
/await
est un meilleur choix.
t.plan()
fournit une valeur dans les cas suivants.
Dans la plupart des cas, c'est une mauvaise idée d'utiliser un débranchement complexe à l'intérieur de vos tests. Une exception notable, c'est pour les tests qui sont générés automatiquement (peut-être venant d'un document JSON). Ci-dessous t.plan()
est utilisé pour s'assurer de l'exactitude du fichier JSON :
import fs from 'fs';
import path from 'path';
const testData = JSON.parse(fs.readFileSync(new URL('./fixtures/test-definitions.json', import.meta.url)));
for (const testDefinition of testData) {
test('foo ou bar', t => {
const result = functionUnderTest(testDefinition.input);
// testDefinition doit attendre `foo` ou `bar` mais pas les deux
t.plan(1);
if (testDefinition.foo) {
t.is(result.foo, testDefinition.foo);
}
if (testDefinition.bar) {
t.is(result.bar, testDefinition.foo);
}
});
}
t.plan()
a beaucoup d'utilisations valables, mais il ne doit pas être utilisé de façon hasardeuse. Une bonne règle est de l'utiliser chaque fois que votre test est compliqué, c'est souvent le cas pour le flux de code. Les tests avec des assertions à l'intérieur des callbacks, d'implémentations if
/then
, des boucles for
/while
et (dans plusieurs cas) dans des blocs try
/catch
, sont tous des bons candidats pour t.plan()
.