TP - Tests unitaires avec Alsatian

Alsatian est un outil de test pour les projets TypeScript. Il permet d’écrire des tests, de les exécuter et de récupérer les résultats sous une forme synthétique. Plus d’informations sur Alsatian ici.

1. Prise en main d’Alsatian avec le projet "Math"

1.1. Récupération du projet "Math"

  1. Dans le répertoire de votre choix, clonez avec git le projet Math disponible à la page Gitlab suivante : https://gitlab.univ-nantes.fr/gl/developpement/math.

  2. Regardons le contenu du projet :

    • Le répertoire src contient le code TypeScript du projet,

    • Le fichier tsconfig.json est présent comme d’habitude, mais avec quelques différences :

      • La ligne "outDir": "build" indique que tout le code JavaScript compilé ira dans un unique répertoire build,

      • La ligne "experimentalDecorators": true est requise pour utiliser Alsatian,

      • La ligne "exclude": [ "node_modules" ] indique à TypeScript de ne pas tenter de compiler les fichiers du répertoire node_modules, car ils contiendront les librairies externes déjà compilées (notamment Alsatian).

    • Enfin, le fichier .gitignore indique à git d’ignorer le répertoire build car nous ne voulons pas commiter les fichiers compilés.

Pour l’instant, ce projet contient juste quelques fonctions TypeScript. Voyons comment ajouter et utiliser l’outil de test Altasian.

1.2. Installation d’Altasian

Pour utiliser Alsatian, il est nécessaire que votre projet de code TypeScript possède une dépendance envers l’outil Alsatian. Pour cela, on va créer un fichier nommé package.json permettant d’indiquer que nous avons besoin d’Alsatian, puis nous allons utiliser un outil appelé npm qui va lire le fichier package.json et ira télécharger Alsatian automatiquement.

  1. Créez un fichier package.json à la racine de votre projet, et contenant les lignes suivantes :

    {
      "scripts": {
        "test": "alsatian ./build/tests/*.js"
      },
      "devDependencies": {
        "alsatian": "^3.2.1"
      }
    }
  2. Dans un terminal, lancez la commande npm install.

Voilà, Alsatian est désormais installé dans votre projet, vous allez pouvoir ajouter et exécuter des tests !

1.3. Ajout et exécution de quelques tests

1.3.1. Ajout de tests

Nous allons maintenant créer et exécuter un premier fichier contenant des tests pour la fonction fibonacci fournie par le projet Math.

  1. Dans le projet Math, créez un répertoire tests. Attention à bien nommer ce répertoire (ne l’appelez pas test) et à bien le placer à la racine, sinon vos tests ne s’executeront pas !

  2. Dans le répertoire tests, créez un nouveau fichier appelé math-tests.ts, et mettez y le contenu suivant :

    import { Expect, Test } from "alsatian";
    import { fibonacci } from "../src/math";
    
    export class FibonacciTests {
    
        @Test("fibonacci(1) doit être égal à 1")
        testFibonacci1() {
            let result = fibonacci(1)
            Expect(result).toBe(1);
        }
    
        @Test("fibonacci(2) doit être égal à 1")
        testFibonacci2() {
            let result = fibonacci(2)
            Expect(result).toBe(1);
        }
    }
  3. Observons le contenu de ce fichier TypeScript :

    • Tout en haut, on utilise import pour aller chercher les fonctions fournies par Alsatian, et pour aller chercher la fonction fibonacci() que nous souhaitons tester.

    • Ensuite on définit et on exporte une classe appelée FibonacciTests dans laquelle nous allons ranger tous nos tests. Nous n’allons pas voir dans le détail ce qu’est une classe, pour le moment retenez juste que c’est un endroit où nous allons ranger tous nos cas de tests.

    • Enfin, on définit chaque cas de test d’une manière similaire à une fonction :

      • On écrit la signature du cas de test avec @Test("description de mon test"), suivi du nom de la fonction de test ;

      • On écrit le contenu du cas de test entre accolades ({}), où on appelle la fonction à tester (ici, fibonacci), et où on utilise les fonctions fournies par Altasian, à savoir :

        • Expect pour donner à Altasian le résultat obtenu,

        • toBe pour indiquer à Altasian quel est le résulta attendu.

Attention, un ensemble de cas de test ne peuvent pas être exécutés comme des fichier TypeScript normaux ! Voyons comment faire pour les exécuter.

1.3.2. Exécution simple via le terminal

Vous pouvez lancer les tests unitaires automatiquement en exécutant la commande suivante depuis un terminal :

npm test

Vous verrez s’afficher un compte rendu de l’exécution des tests : combien ont réussi, combien ont échoué, et lesquels ont échoué.

La commande npm test va en fait aller chercher la commande test au sein du fichier package.json ajouté précédemment. Cette commande test exécute Alsatian sur tous les tests présents dans le répertoire tests.

1.3.3. Exécution et débogage via Visual Studio Code

Il est également possible d’exécuter les tests directement depuis l’interface graphique de Visual Studio Code sans avoir besoin d’un terminal. Cela nécessite d’ouvrir une vue appelée NPM scripts qui n’est pas ouverte par défaut dans l’interface.

  • Pour ouvrir la vue NPM scripts:

    • Portez votre regard en haut à gauche sur votre section Explorer, qui ressemble normalement à ceci :

      explorer1
    • Repérez en haut à gauche l’icône avec trois points, et cliquez dessus.

    • Un menu s’ouvre permettant de choisir quelles vues on souhaite afficher. Cliquez sur la vue NPM Scripts (la seule non activée) pour l’activer.

  • Attention, c’est très discret : constatez que vous avez désormais tout en bas de votre section Explorer une nouvelle vue repliée appelée NPM Scripts :

    explorer2
    • Cliquez dessus, et vous verrez alors une liste contenant uniquement le script test :

      npm scripts
  • Pour lancer une exécution ou un déboguage :

    • Dans la vue NPM Scripts, mettez votre curseur sur la ligne avec le script test (sans cliquer dessus),

    • Deux petites icônes s’affichent sur la droite :

      • L’icône "insecte" permet d’exécuter les tests en mode débogage, donc avec possibilité de mettre l’exécution en pause à l’aide de points d’arrêt, et possibilité d’exécuter ligne par ligne (voir section suivante du TP pour plus de détails),

      • L’icône "lecture" permet d’exécuter les tests normalement.

Lorsque vous lancez vos tests de cette manière, et que vos tests échouent, vous pouvez constater qu’un long message d’erreur comme celui-ci s’affiche alors :

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! @ test: `alsatian ./build/tests/*.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @ test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/utiliateur/.npm/_logs/2021-02-25T13_50_32_226Z-debug.log
The terminal process "/bin/sh '-c', 'npm run test'" terminated with exit code: 1.

Ce message d’erreur peut être ignoré, il est tout à fait normal qu’il s’affiche lorsqu’un test échoue. Mais il faut reconnaître que ce n’est pas très joli à voir ni très utile.

Si vous souhaitez ne plus avoir ce message d’erreur, il suffit de créer à la racine de votre projet un fichier .npmrc et d’y mettre le contenu suivant :

loglevel=silent

1.4. Comment déboguer un test en pratique ?

Que faire lorsqu’un test est bien codé, mais que le test échoue ? Cela signifie qu’il existe un défaut dans le programme testé par le test, et qu’il faut le localiser puis le corriger !

Deux possibilités :

  • Soit on va lire les lignes de code du programme, et tenter de comprendre par cette simple lecture ce qui ne va pas. C’est souvent suffisant pour des problèmes simples.

  • Soit on utilise le débogueur pour exécuter le programme ligne par ligne, et pour observer en détail ce qu’il se passe, et comprendre ce qui ne fonctionne pas comme prévu.

Imaginons que l’on souhaite enquêter sur l’exécution du test testFibonnacci1. On souhaite utiliser le débogueur pour mieux comprendre ce qu’il se passe. Voyons comment nous y prendre :

  • Mettez un point d’arrêt sur la première ligne de testFibonnacci1, c’est à dire la ligne avec un l’appel à la fonction fibonacci(). Pour cela, cliquez sur la colonne à gauche de la ligne, et cela fera apparaître un point rouge comme ceci :

    breakpoint
  • Lancez vos tests en mode débogage (voir la section suivante pour l’usage de la vue NPM Tests). L’exécution va très rapidement se mettre en pause sur la ligne contenant le point d’arrêt, ce qui donne ce résultat :

    pause1
  • Utilisez le bon bouton de la mini-barre d’outils de débogage (ou bien la touche F11 directement) pour effectuer l’action Step Into. Cette action a pour but de rentrer à l’intérieur d’une fonction appelée sur la ligne actuellement en pause, qui est ici la fonction fibonacci. Autrement dit, Step Into va poursuivre l’exécution très brièvement, et mettre de nouveau en pause au tout début de l’exécution de la fonction fibonacci. On arrive alors ici :

    pause2
  • L’enquête peut alors commencer ! Différents outils sont à notre disposition :

    • L’action Step Over qui permet d’exécuter la ligne actuellement en pause, et de passer à la ligne suivante. On peut ainsi exécuter notre fonction fibonacci ligne après ligne.

    • L’action Step Into peut ici aussi être utilisée pour plonger à l’intérieur d’un appel de fonction, comme par exemple sur la ligne return fibonacci(n-1) afin de plonger dans le 2e appel effectué récursivement sur la fonction fibonacci.

    • La vue Variables, située à gauche lorsqu’on est dans le mode Run, nous permet savoir ce que contiennent toutes nos variables. Pour fibonnacci, elle ressemble au départ à ceci :

      variables

      On peut voir que la valeur de n est actuellement 1, ce qui est logique puisque la fonction a été appelée avec fibonacci(1). Mais le plus intéressant est que cette vue se mettra à jour à chaque exécution de ligne, ce qui permet de suivre exactement comment les variables évoluent !

Vous voilà parfaitement outillés pour enquêter sur les bugs que peuvent contenir vos programmes 😃.

1.5. Écriture de nouveaux tests

  1. Dans le fichier tests/math-tests.ts que vous avez créé, ajoutez de nouveaux tests pour la fonction fibonacci.

  2. Exécutez vos tests. Est-ce qu’ils passent tous ?

  3. Si certains de vos tests ne passent pas, trouvez l’erreur qui existe dans la fonction fibonacci, et corrigez là ! N’hésitez pas à aller voir la page Wikipédia sur la suite de Fibonacci pour comprendre ce que doit faire cette fonction.

  4. Relancez vos tests après votre correction. Ils doivent désormais tous passer 😃.

2. Écriture et test d’autres fonctions

Continuons avec de nouvelles fonctions et de nouveaux cas de tests.

2.1. Âge et Année bissextile

  1. Écrire dans un fichier .ts le code d’une fonction qui calcule l’âge d’une personne, en faisant l’hypothèse que la date du jour est le 10/02/2020. Écrire les cas de tests possibles pour une telle fonction dans un fichier .ts dans le répertoire tests.

  2. Écrire dans un fichier .ts le code d’une fonction qui renvoie true si une année est bissextile. Écrire les cas de tests possibles pour une telle fonction dans un fichier .ts dans le répertoire tests.

2.2. Former un triangle

  • Étant données 3 longueurs, nous voulons vérifier que la construction d’untriangle est possible. Pour cela, nous allons écrire une fonction isTriangle(a: number, b: number, c: number): boolean qui renvoie vrai ssi il est possible de construire un triangle en utilisant les 3 longueurs passées en paramètre.

  • Écrire les cas de tests possibles pour une telle fonction dans un fichier .ts dans le répertoire tests.

2.3. Entiers palindromes

  • Écrire une fonction qui permet d’écrire un entier à l’envers. Écrire les cas de tests possibles pour une telle fonction dans un fichier .ts dans le répertoire tests.

  • Écrire une fonction qui permet de vérifier qu’un entier est un palindrome. Écrire les cas de tests possibles pour une telle fonction dans un fichier .ts dans le répertoire tests.