Nous savons tous que nous devrions tester notre code, mais nous ne le faisons pas réellement. Je suppose qu’il est juste de dire que la plupart d’entre nous l’a remis parce que, neuf fois sur dix, cela signifie qu’il faut apprendre un autre concept. Dans ce tutoriel, je vais vous présenter un excellent petit framework pour tester facilement votre code JavaScript..
Au fait, saviez-vous que vos erreurs JavaScript peuvent être corrigées rapidement et facilement par un expert d’Envato Studio?
ThemeManiac, par exemple, corrige les erreurs Java ou les problèmes de compatibilité du navigateur sur votre site Web ou votre application Web. Les corrections peuvent être effectuées très rapidement, en fonction de la complexité et des informations disponibles. Il peut également réorganiser vos scripts et créer une expérience utilisateur totalement nouvelle. Il a effectué plus de 1 000 travaux sur Envato Studio et 99% de ses clients l'ont recommandé..
Aujourd'hui, nous allons en apprendre davantage sur le cadre de test Jasmine BDD. Mais nous nous arrêtons ici pour faire un détour d’abord, pour parler très brièvement, de BDD et de TDD. Si vous ne connaissez pas ces acronymes, ils signifient Développement axé sur le comportement et Développement piloté par les tests. Je suis en train de comprendre en quoi consiste chacune de ces pratiques et en quoi elles sont différentes, mais voici quelques-unes des différences fondamentales:
BDD et TDD? représenter Développement axé sur le comportement et Développement piloté par les tests.
TDD dans sa forme la plus simple est juste ceci:
C'est assez facile à comprendre, hein?
BDD est un peu plus complexe: si je comprends bien, je ne pense pas que vous ou moi, en tant que développeur unique, puissions le pratiquer pleinement. c'est plus une affaire d'équipe. Voici quelques-unes des pratiques de BDD:
Pour en savoir plus, vous pouvez lire le vaste article Wikipedia (à partir duquel ces points ont été tirés).
Tout cela pour dire que, bien que Jasmine se présente comme un framework BDD, nous allons l’utiliser de manière plus TDD. Cela ne signifie pas que nous l'utilisons mal, cependant. Une fois que nous aurons terminé, vous pourrez tester votre JavaScript facilement? et j'espère que vous le ferez!
Jasmine prend beaucoup de repères de Rspec.
Si vous connaissez Rspec, le de facto Avec le framework BDD, vous verrez que Jasmine prend beaucoup de signaux de Rspec. Les tests au jasmin sont principalement composés de deux parties: décrire
des blocs et il
des blocs. Voyons comment cela fonctionne.
Nous examinerons quelques tests plus proches de la vie réelle, mais pour le moment, nous allons rester simples:
describe ('opérateur d'addition JavaScript', function () it ('ajoute deux nombres ensemble', function () expect (1 + 2) .toEqual (3);););
Les deux décrire
et il
les fonctions prennent deux paramètres: une chaîne de texte et une fonction. La plupart des frameworks de test essaient de lire autant que possible l'anglais, et vous pouvez le voir avec Jasmine. Tout d'abord, notez que la chaîne passée à décrire
et la chaîne passée à il
forme une phrase (de sorte):? L'opérateur d'addition JavaScript ajoute deux nombres ensemble.? Ensuite, nous montrons comment.
À l'intérieur de cela il
bloquer, vous pouvez écrire tout le code de configuration dont vous avez besoin pour votre test. Nous n'en avons pas besoin pour cet exemple simple. Une fois que vous êtes prêt à écrire le code de test, vous commencerez par le attendre
fonction, en passant ce que vous testez. Remarquez comment cela forme aussi une phrase: on s'attend à ce que 1 + 2 soit égal à 3.?
Mais je devance nous-mêmes. Comme je l'ai dit, quelle que soit la valeur que vous transmettez attendre
sera testé. La méthode que vous appelez, en dehors de la valeur renvoyée par attendre
, sera déterminé par quel test est exécuté. Ce groupe de méthodes s'appelle les «correspondants» et nous en examinerons plusieurs aujourd'hui. Dans ce cas, nous utilisons le égaler
matcher, qui vérifie que la valeur passée à attendre
et la valeur passée à égaler
sont la même valeur.
Je pense que vous êtes prêt à passer au niveau supérieur, alors mettons en place un projet simple utilisant Jasmine.
Le jasmin peut être utilisé seul; ou vous pouvez l'intégrer à un projet Rails. Nous ferons le premier. Bien que Jasmine puisse fonctionner en dehors du navigateur (pensez à Node, entre autres), nous pouvons obtenir un très joli petit modèle avec le téléchargement..
Alors, rendez-vous sur la page de téléchargement autonome et obtenez la dernière version. Vous devriez obtenir quelque chose comme ça:
Vous trouverez les fichiers de framework Jasmine dans le répertoire lib
dossier. Si vous préférez structurer vos projets différemment, veuillez le faire; mais nous allons garder cela pour l'instant.
En fait, un exemple de code est câblé dans ce modèle de projet. L'actuel? JavaScript (le code que nous voulons tester) peut être trouvé dans le src
sous-répertoire; nous y mettrons le nôtre sous peu. Le code de test-le spécifications-aller dans le spec
dossier. Ne t'inquiète pas pour le SpecHelper.js
déposer pour l'instant; on y reviendra.
Cette SpecRunner.html
fichier est ce qui exécute les tests dans un navigateur. Ouvrez-le (et cochez la case "passé" dans le coin supérieur droit), et vous devriez voir quelque chose comme ça:
Cela nous montre que tous les tests du projet exemple sont réussis. Une fois ce didacticiel terminé, je vous recommande d’ouvrir la spec / PlayerSpec.js
déposer et parcourir ce code. Mais pour le moment, essayons cet essai d'écriture test.
convert.js
dans le src
dossier.convertSpec.js
dans le spec
dossier,SpecRunner.html
déposer et renommer SpecRunner.original.html
.Supprimez les liens vers les exemples de fichiers de projet dans SpecRunner.html
et ajoutez ces lignes:
Nous sommes maintenant prêts à créer une mini-bibliothèque qui convertira les unités de mesure. Nous allons commencer par écrire les tests pour notre mini-bibliothèque.
Alors, écrivons nos tests, allons-nous?
describe ("Convertir une bibliothèque", function () decrire ("convertisseur de distance", function () ); decrire ("convertisseur de volume", function () ););
Nous commençons par ceci; nous testons notre Convertir
bibliothèque. Vous remarquerez que nous imbriquons décrire
déclarations ici. Ceci est parfaitement légal. C'est en fait un excellent moyen de tester différentes fonctionnalités du même code. Au lieu de deux séparés décrire
appels pour Convertir
Les conversions de distance et de volume de la bibliothèque, nous pouvons avoir une suite de tests plus descriptive comme celle-ci.
Maintenant, sur les tests réels. Je vais répéter l'intérieur décrire
appelle ici pour votre commodité.
describe ("convertisseur de distance", function () it ("convertit les pouces en centimètres", function () expect (Convert (12, "in"). en ("cm")). toEqual (30.48);) ; it ("convertit des centimètres en verges", function () expect (Convert (2000, "cm"). en ("verges")). toEqual (21.87);));
Voici nos tests pour les conversions à distance. Il est important de noter quelque chose ici: nous n’avons pas écrit un grain de code pour notre Convertir
bibliothèque pour le moment, alors dans ces tests, nous faisons plus que vérifier pour voir si cela fonctionne: nous décidons en fait de la manière dont elle sera utilisée (et donc implémentée). Voici comment nous avons décidé d'effectuer nos conversions:
Convertir(, ).à( )
Oui, je me fie à la façon dont Jasmine a mis en œuvre ses tests, mais je pense que c'est un format agréable. Ainsi, dans ces deux tests, j’ai moi-même effectué les conversions (avec une calculatrice) pour voir quels devraient être les résultats de nos appels. Nous utilisons le égaler
matcher pour voir si nos tests réussissent.
Voici les tests de volume:
describe ("convertisseur de volume", function () it ("convertit les litres en gallons", function () expect (Converti (3, "litres").. en ("gallons")). toEqual (0.79);) ; it ("convertit des gallons en tasses", function () expect (Converti (2, "gallons"). en ("tasses")). toEqual (32);));
Et je vais ajouter deux autres tests dans notre plus haut niveau décrire
appel:
it ("génère une erreur lorsqu’on transmet une unité from inconnue", function () var testFn = function () Convertir (1, "dollar"). en ("yens"); expect (testFn) .toThrow ( new Error ("non reconnu par l'unité"));); it ("génère une erreur lorsqu’on transmet une unité inconnue", function () var testFn = function () Convertir (1, "cm"). en ("furlongs"); expect (testFn) .toThrow ( nouvelle erreur ("unité non reconnue")););
Ils vérifient les erreurs qui devraient être émises lorsque des unités inconnues sont passées dans le Convertir
fonction ou la à
méthode. Vous remarquerez que je suis en train d'envelopper la conversion réelle dans une fonction et de le transmettre à la attendre
une fonction. C'est parce que nous ne pouvons pas appeler la fonction en tant que attendre
paramètre; nous devons lui donner une fonction et le laisser appeler la fonction elle-même. Puisque nous avons besoin de passer un paramètre à celui à
fonction, nous pouvons le faire de cette façon.
L'autre chose à noter est que je présente un nouveau matcher: lancer
, qui prend un objet d'erreur. Nous allons bientôt regarder d'autres joueurs.
Maintenant, si vous ouvrez SpecRunner.html
dans un navigateur, vous obtiendrez ceci:
Génial! Nos tests échouent. Maintenant, ouvrons notre convert.js
déposer et faire du travail:
function Convert (nombre, fromUnit) conversions var = distance: mètres: 1, cm: 0,01, pieds: 0,3048, pouces: 0,0254, yards: 0,9144, volume: litres: 1, gallons: 3,785411784, tasses: 0,236588236 , betweenUnit = false, type, unité; for (saisissez les conversions) if (conversions (type)) if ((unité = conversions [type] [fromUnit])) betweenUnit = number * unit * 1000; return to: function (toUnit) if (betweenUnit) for (saisissez les conversions) if (conversions.hasOwnProperty (type)) if ((unit = conversions [type] [toUnit])) retour fix (betweenUnit / (unit * 1000)); jeter une nouvelle erreur ("unité non reconnue"); else lance new Error ("non reconnu par l'unité"); function fix (num) return parseFloat (num.toFixed (2)); ;
Nous n'allons pas vraiment en discuter, parce que nous apprenons Jasmine ici. Mais voici les points principaux:
verges: 0,9144
, vous savez que c'est combien de mètres il y a dans un mètre. Ensuite, pour convertir des verges en centimètres, par exemple, nous multiplions cours
par le premier paramètre (pour obtenir le nombre de mètres) puis diviser le produit par cm
, le nombre de mètres en centimètre. De cette façon, nous n'avons pas à stocker les taux de conversion pour chaque paire de valeurs. Cela facilite également l'ajout ultérieur de nouvelles valeurs.deUnit
à la bonne clé.Convertir
fonction, nous stockons la valeur intermédiaire dans entre les unités
, qui est initialisé à faux
. De cette façon, si nous n'avons pas le deUnit
, entre les unités
sera faux
entrer dans le à
méthode, et donc une erreur avec être jetée.toUnit
, une erreur différente sera levée. Sinon, nous diviserons comme nécessaire et renverrons la valeur convertie.Maintenant, retournez à SpecRunner.html
et rechargez la page. Vous devriez maintenant voir ceci (après vérification? Afficher passé?):
Voilà! Nos tests passent. Si nous développions un projet réel ici, nous écrivions des tests pour une certaine fonctionnalité, les passions, des tests pour un autre contrôle, les passions, etc. Mais comme il s’agissait d’un exemple simple, nous venons de le faire. tout d'un coup swoop.
Et maintenant que vous avez vu cet exemple simple d'utilisation de Jasmine, examinons quelques autres fonctionnalités proposées..
Jusqu'à présent, nous avons utilisé deux matcheurs: égaler
et lancer
. Il y en a bien sûr beaucoup d'autres. En voici quelques-unes que vous trouverez probablement utiles. vous pouvez voir la liste complète sur le wiki.
Si vous voulez juste vous assurer qu'une variable ou une propriété est définie, il y a un indicateur pour cela. Il y a aussi un pour confirmer qu'une variable ou une propriété est indéfini
.
it ("est défini", fonction () var nom = "Andrew"; attend (nom) .toBeDefined ();) it ("n'est pas défini", fonction () nom var.; attend (nom) .toBeUndefined (););
Si quelque chose devait être vrai ou faux, ces joueurs le feront.
it ("est vrai", function () expect (Lib.isAWeekDay ()). toBeTruthy ();); it ("est faux", function () expect (Lib.finishedQuiz) .toBeFalsy (););
Pour tous vous numérotez les gens. Vous savez comment cela fonctionne:
it ("est inférieur à 10", function () expect (5) .toBeLessThan (10);); it ("est supérieur à 10", function () expect (20) .toBeGreaterThan (10););
Vous avez du texte en sortie qui devrait correspondre à une expression régulière? le correspondre
matcher est prêt et disposé.
it ("affiche le texte correct", function () expect (cart.total ()). toMatch (/ \ $ \ d *. \ d \ d /););
Celui-ci est très utile. Il vérifie si un tableau ou une chaîne contient un élément ou une sous-chaîne.
it ("devrait contenir des oranges", function () expect (["pommes", "oranges", "poires"])). toContain ("oranges"););
Il y a aussi quelques autres correspondants que vous pouvez trouver dans le wiki. Mais si vous voulez un matcher qui n'existe pas? Vraiment, vous devriez être capable de faire à peu près n'importe quoi avec du code d'installation et les correspondants fournis par Jasmine, mais il est parfois plus agréable de résumer une partie de cette logique pour obtenir un test plus lisible. Heureusement (enfin, pas du tout), Jasmine nous permet de créer nos propres matchers. Mais pour ce faire, nous devons d'abord apprendre un petit quelque chose.
Souvent, lorsque vous testez une base de code, vous souhaitez exécuter quelques lignes de code de configuration pour chaque test d'une série. Il serait douloureux et prolixe de devoir copier cela pour chaque il
Jasmine a donc une petite fonctionnalité pratique qui nous permet de désigner le code à exécuter avant ou après chaque test. Voyons comment cela fonctionne:
describe ("MyObject", function () var obj = new MyObject (); beforeEach (function () obj.setState ("clean");); it ("change d'état", function () obj.setState ("dirty"); expect (obj.getState ()). toEqual ("dirty");) it ("ajoute des états", function () obj.addState ("packaged"); expect (obj.getState ( )). toEqual (["clean", "emballé"]);));
Dans cet exemple artificiel, vous pouvez voir comment, avant chaque test, l’état de obj
est réglé pour? nettoyer ?. Si nous ne le faisions pas, la modification apportée à un objet lors d'un test précédent persisterait au test suivant par défaut. Bien sûr, nous pourrions aussi faire quelque chose de similaire avec le Après chaque
une fonction:
describe ("MyObject", function () var obj = new MyObject ("clean"); // définit l'état initial afterEach (function () obj.setState ("clean");); it ("change d'état" , function () obj.setState ("dirty"); expect (obj.getState ()). toEqual ("dirty");) il ("ajoute des états", function () obj.addState ("emballé" ); expect (obj.getState ()). toEqual (["clean", "packaged"]);));
Ici, nous configurons l’objet pour commencer, puis nous le corrigeons après chaque test. Si tu veux le MyObject
afin que vous puissiez essayer ce code, vous pouvez le trouver ici dans un gist GitHub.
Comme nous l'avons dit précédemment, les correspondants clients seraient probablement utiles par moments. Alors écrivons-en un. Nous pouvons ajouter un matcher soit dans un Avant chaque
appeler ou un il
appelez (eh bien, je suppose que vous pourrait le faire dans un Après chaque
appeler, mais cela n’aurait pas beaucoup de sens). Voici comment vous commencez:
beforeEach (function () this.addMatchers (););
Assez simple, hein? Nous appelons this.addMatchers
, en lui passant un paramètre d'objet. Chaque clé de cet objet deviendra le nom d'un matcher et la fonction associée (la valeur) indiquera comment elle est exécutée. Supposons que nous voulions créer un correcteur qui vérifie si un nombre est compris entre deux autres. Voici ce que vous écririez:
beforeEach (function () this.addMatchers (toBeBetween: function (rangeFloor, rangeCeiling)) if (rangeFloor> rangeCeiling) var temp = rangeFloor; rangeFloor = rangeCeiling; rangeCeiling = temp; retourne ceci. réel < rangeCeiling; ); );
Nous prenons simplement deux paramètres, nous nous assurons que le premier est plus petit que le second et renvoyons une instruction boolean qui vaut true si nos conditions sont remplies. La chose importante à noter ici est la façon dont nous obtenons la valeur qui a été transmise à la attendre
une fonction: this.actual
.
it ("est compris entre 5 et 30", function () expect (10) .toBeBetween (5, 30);); il ("est compris entre 30 et 500", function () s'attendre à (100) .toBeBetween (500, 30););
C'est ce que le SpecHelper.js
le fichier fait; il a un avant chaque
appel qui ajoute le matcher tobePlaying ()
. Vérifiez-le!
Jasmine offre bien d’autres possibilités: adaptateurs, espions, spécifications asynchrones, etc. Je vous recommande d'explorer le wiki si cela vous intéresse. Il existe également quelques bibliothèques d'accompagnement facilitant les tests dans le DOM: Jasmine-jQuery et Jasmine-fixture (qui dépend de Jasmine-jQuery)..
Donc, si vous ne testez pas votre JavaScript jusqu'à présent, le moment est idéal pour commencer. Comme nous l'avons vu, la syntaxe simple et rapide de Jasmine simplifie les tests. Il n'y a aucune raison pour que vous ne le fassiez pas, maintenant, y at-il?
Si vous souhaitez approfondir votre développement JavaScript, pourquoi ne pas consulter la gamme d'articles JavaScript sur Envato Market? Il existe des milliers de scripts, d'applications et d'extraits de code pour vous aider.