Après avoir modifié ou ajouté du code, vous devez exécuter les tests unitaires existants et envisager d'en écrire d'autres. Tous les tests sont exécutés sur les versions non compressées du code.
Il existe deux ensembles de tests unitaires : les tests JavaScript et les tests du générateur de blocs.
Tests JS
Les tests JS confirment le fonctionnement des fonctions JavaScript internes dans le de base. Nous utilisons Mocha pour exécuter des tests unitaires, Sinon pour créer des bouchons de dépendances et Chai pour émettre des assertions sur le code.
Exécution des tests
Dans les échantillons par blocs et par blocs, npm run test exécute les tests unitaires. Dans
de façon bloc, d'autres tests, tels que le linting et la compilation, seront aussi exécutés. Vous pouvez également ouvrir tests/mocha/index.html dans un navigateur pour exécuter de manière interactive tous les tests mocha.
Écriture des tests
Nous utilisons l'interface Mocha TDD pour exécuter les tests. Les tests sont organisés en suites, qui peuvent contenir à la fois des sous-suites et/ou des tests supplémentaires. En général, chaque composant de Blockly (comme toolbox ou workspace) possède son propre fichier de test contenant une ou plusieurs suites. Chaque suite peut avoir un setup et un teardown
qui sera appelée avant et après, respectivement, chaque test dans ce
suite.
Assistants de test
Nous proposons plusieurs fonctions d'assistance spécifiques à Blockly qui peuvent être utiles lors de l'écriture de tests. Vous les trouverez dans core et dans blockly-samples.
Les fonctions d'assistance incluent sharedTestSetup et sharedTestTeardown, qui
doivent obligatoirement être appelés avant et après vos tests (voir la section
).
sharedTestSetup :
- Configure des faux minuteurs sinon (dans certains tests, vous devrez utiliser
this.clock.runAll). - Stubs Blockly.Events.fire doit se déclencher immédiatement (configurable).
- Configure le nettoyage automatique des types de blocs définis via
defineBlocksWithJsonArray. - Déclaration de quelques propriétés sur le contexte
thisqui sont censées être accessibles :this.clock(mais ne doit pas être restauré, sinon cela entraînera des problèmes danssharedTestTeardown)this.eventsFireStubthis.sharedCleanup(à utiliser avecaddMessageToCleanupetaddBlockTypeToCleanup) (REMARQUE: vous n'avez pas besoin d'utiliseraddBlockTypeToCleanupsi vous avez défini le bloc en utilisantdefineBlocksWithJsonArray)
La fonction comporte un paramètre options facultatif pour configurer la configuration. Actuellement, il n'est utilisé que pour déterminer si Blockly.Events.fire doit être instancié immédiatement (par défaut).
sharedTestTeardown :
- Élimine l'espace de travail
this.workspace(selon l'emplacement où il a été défini, consultez la section "Exigences de test" pour en savoir plus). - Restaure toutes les bouchons.
- Nettoie tous les types de blocs ajoutés via
defineBlocksWithJsonArrayetaddBlockTypeToCleanup. - Nettoie tous les messages ajoutés via
addMessageToCleanup.
Exigences concernant les tests
- Chaque test doit appeler
sharedTestSetup.call(this);sur la première ligne du de la suite externe etsharedTestTeardown.call(this);en tant que dernière ligne de la suppression de la suite de plus haut niveau pour un fichier. - Si vous avez besoin d'un espace de travail avec une boîte à outils générique, vous pouvez utiliser l'une des
boîtes à outils prédéfinies
sur le
index.htmlde test. Vous trouverez un exemple ci-dessous. - Vous devez supprimer
this.workspacecomme il se doit. Dans la plupart des tests, vous définirezthis.workspacedans la suite la plus externe et l'utiliserez pour tous les tests suivants. Toutefois, dans certains cas, vous pouvez le définir ou le redéfinir dans une suite interne (par exemple, l'un de vos tests nécessite un espace de travail avec des options différentes de celles que vous avez initialement configurées). Il doit être jeté à la fin du test.- Si vous définissez
this.workspacedans la suite la plus externe et ne la redéfinissez jamais, aucune autre action n'est requise. Elle sera automatiquement supprimée parsharedTestTeardown - Si vous définissez
this.workspacepour la première fois dans une suite interne (c'est-à-dire que vous ne l'avez pas défini dans la suite la plus externe), vous devez vous en débarrasser manuellement en appelantworkspaceTeardown.call(this, this.workspace)lors du démontage de cette suite. - Si vous définissez
this.workpacedans la suite de plus haut niveau, puis que vous redéfinissez dans une suite de tests interne, vous devez d'abord appelerworkspaceTeardown.call(this, this.workspace)avant de la redéfinir pour supprimer l'espace de travail d'origine défini dans la suite de premier niveau. Vous devez également supprimer manuellement la nouvelle valeur en appelant à nouveauworkspaceTeardown.call(this, this.workspace)lors du démontage de cette suite interne.
- Si vous définissez
Structure des tests
Les tests unitaires suivent généralement une structure définie, qui peut se résumer en organiser, agir, affirmer.
- Organisation: permet de définir l'état du monde et les conditions requises pour le comportement testé.
- Action : appelez le code à tester pour déclencher le comportement à tester.
- Assert : effectuez des assertions sur la valeur renvoyée ou les interactions avec des objets simulés afin de vérifier leur exactitude.
Dans un test simple, il n'y a peut-être pas de comportement à organiser, et les étapes d'action et d'assertion peuvent être combinées en insérant l'appel du code testé dans l'assertion. Pour les cas plus complexes, vos tests seront plus lisibles si vous respectez ces trois étapes.
Voici un exemple de fichier de test (simplifié par rapport à la réalité).
suite('Flyout', function() {
setup(function() {
sharedTestSetup.call(this);
this.toolboxXml = document.getElementById('toolbox-simple');
this.workspace = Blockly.inject('blocklyDiv',
{
toolbox: this.toolboxXml
});
});
teardown(function() {
sharedTestTeardown.call(this);
});
suite('simple flyout', function() {
setup(function() {
this.flyout = this.workspace.getFlyout();
});
test('y is always 0', function() {
// Act and assert stages combined for simple test case
chai.assert.equal(this.flyout.getY(), 0, 'y coordinate in vertical flyout is 0');
});
test('x is right of workspace if flyout at right', function() {
// Arrange
sinon.stub(this.flyout.targetWorkspace, 'getMetrics').returns({
viewWidth: 100,
});
this.flyout.targetWorkspace.toolboxPosition = Blockly.TOOLBOX_AT_RIGHT;
this.flyout.toolboxPosition_ = Blockly.TOOLBOX_AT_RIGHT;
// Act
var x = this.flyout.getX();
// Assert
chai.assert.equal(x, 100, 'x is right of workspace');
});
});
});
Points à noter concernant cet exemple:
- Une suite peut contenir d'autres suites avec des
setupet desteardownsupplémentaires méthodes. - Chaque suite et chaque test possède un nom descriptif.
- Les assertions Chai permettent d'effectuer des assertions sur le code.
- Vous pouvez fournir un argument de chaîne facultatif qui s'affichera en cas d'échec du test. Cela permet de déboguer plus facilement les tests défectueux.
- L'ordre des paramètres est
chai.assert.equal(actualValue, expectedValue, optionalMessage). Si vous échangezactualetexpected, les messages d'erreur n'auront aucun sens.
- Sinon, il est utilisé pour bouchonner les méthodes lorsque vous ne souhaitez pas appeler le vrai code. Dans cet exemple, nous ne voulons pas appeler la fonction de métriques réelles, car elle n'est pas pertinente pour ce test. Nous ne nous soucions que de la façon dont les résultats
la méthode testée. Sinon, il remplace la fonction
getMetricspour renvoyer une réponse prédéfinie que nous pouvons facilement vérifier dans nos assertions de test. - Les méthodes
setupde chaque suite ne doivent contenir que la configuration générique qui s'applique à tous les tests. Si un test d'un comportement particulier repose sur une certaine condition, cette condition doit être clairement indiquée dans le test concerné.
Tests de débogage
- Vous pouvez ouvrir les tests dans un navigateur et utiliser les outils pour les développeurs pour définir et déterminez si vos tests échouent de manière inattendue (ou réussissent de manière inattendue !).
Définissez
.only()ou.skip()sur un test ou une suite pour n'exécuter que cet ensemble de tests. ou d'ignorer un test. Exemple :suite.only('Workspace', function () { suite('updateToolbox', function () { test('test name', function () { // ... }); test.skip('test I don’t care about', function () { // ... }); }); });N'oubliez pas de les supprimer avant de valider votre code.
Tests du générateur de blocs
Chaque bloc possède ses propres tests unitaires. Ces tests vérifient que les blocs génèrent code que les fonctions prévues.
- Chargez
tests/generators/index.htmldans Firefox ou Safari. Notez que Chrome et Opera comportent des restrictions de sécurité qui empêchent le chargement des tests à partir du fichier local "file://" (problèmes 41024 et 47416). - Dans le menu déroulant, choisissez la partie du système à tester en fonction de votre situation. cliquez sur "Charger". Les blocages doivent s'afficher dans l'espace de travail.
- Cliquez sur "JavaScript".
Copiez et exécutez le code généré dans une console JavaScript. Si la sortie se termine avec "OK", le test a réussi. - Cliquez sur "Python".
Copiez et exécutez le code généré dans un interpréteur Python. Si le résultat se termine par "OK", le test a réussi. - Cliquez sur "PHP".
Copiez et exécutez le code généré dans un interpréteur PHP. Si le résultat se termine par "OK", le test a réussi. - Cliquez sur "Lua".
Copiez et exécutez le code généré dans un interpréteur Lua. Si la sortie se termine par "OK", le test a réussi. - Cliquez sur "Dart".
Copiez et exécutez le code généré dans un interpréteur Dart. Si le résultat se termine par "OK", le test a réussi.
Modifier les tests du générateur de blocs
- Chargez
tests/generators/index.htmldans un navigateur. - Sélectionnez la partie du système concernée dans le menu déroulant, puis cliquez sur "Charger". Les blocages doivent s'afficher dans l'espace de travail.
- Apportez des modifications ou des ajouts aux blocs.
- Cliquez sur "XML".
- Copiez le code XML généré dans le fichier approprié dans
tests/generators/.