June 10, 2023

Branches Tech

Engagé pour la qualité technologique

Monorepos JS en prod 4 : tests unitaires avec Mocha et Should.js

8 min read
Monorepos JS en prod 4 : tests unitaires avec Mocha et Should.js

Les tests unitaires sont essentiels pour chaque projet à long terme et vous permettent de dérouler les fonctionnalités de votre code dans des unités testables isolées. En effet, l’objectif principal d’un test unitaire est de vérifier si un morceau de code indépendant se compile au comportement attendu. En tant que tels, les tests unitaires doivent avoir une portée étroite et couvrir tous les cas possibles.

Ici, nous couvrirons et comparerons les tests unitaires en JavaScript et CoffeeScript en utilisant le populaire Moka cadre de test en combinaison avec la bibliothèque d’assertions Devrait.js . Dans le prochain article de notre série, nous discuterons de l’intégration CI/CD dans le contexte des monodépôts :

Tests unitaires avec Mocha et Should.js

Tandis que le gatsby-remark-title-to-frontmatter est utilisé depuis un certain temps sur plusieurs de nos sites Web et peut être considéré comme stable, il semble gênant de publier une version stable 1.0.0 sans envoyer de tests unitaires.

Je commence généralement par écrire des tests unitaires avant de commencer tout développement. Quelle honte n’est-ce pas ? Pas vraiment. Cette pratique apporte quelques avantages à long terme. En effet, couvrir votre base de code avec un ensemble complet de tests unitaires aidera définitivement à garder votre code propre et fonctionnel et facilitera tout processus de refactorisation.

Comme indiqué ci-dessus, nous allons utiliser Moka pour les tests unitaires et Devrait.js pour les affirmations. Mais n’hésitez pas à utiliser vos outils préférés. En effet, il existe plusieurs bibliothèques et outils alternatifs, notamment Plaisanter et Chaï. Avant de commencer avec notre exemple, passons d’abord à l’intérieur du gatsby-remark/title-to-frontmatter annuaire:

cd gatsby-remark/title-to-frontmatter

Ensuite, nous devons ajouter Mocha et Should.js à nos dépendances de package :

Comme vous pouvez le voir yarn La commande a été exécutée avec quelques arguments. La -D ou --dev permet l’installation d’un ou plusieurs packages dans le devDependencies de la packages.json trouve dans notre gatsby-remark/title-to-frontmatter forfait.

De plus, il est pratique de modifier la configuration de Mocha de manière à ce que chaque fois que vous l’importez, elle charge automatiquement la bibliothèque d’assertions Should.js. Il y a plusieurs endroits où vous pouvez le faire, mais je modifie le package.json fichier comme suit :


  ...
  "mocha": 
    "throw-deprecation": true,
    "require": [
      "should"
    ],
    "inline-diffs": true,
    "timeout": 40000,
    "reporter": "spec",
    "recursive": true
  

Maintenant, Should.js sera automatiquement chargé avec mocha Grace à require propriété. Par conséquent, nous n’aurons pas besoin de l’exiger dans nos modules de test.

Les tests unitaires sont des fonctions uniques. A Moka, c’est le it fonction. Les fonctions de test sont regroupées avec la fonction de description. Un test doit couvrir une caractéristique de la manière la plus lisible et la plus précise. Lorsque cela est possible, ils doivent être autonomes sans nécessiter d’indices externes mais au contraire, ils doivent recréer les conditions de leur succès. Je préfère avoir tout dans mes fonctions de test et éviter les appareils stockés dans un endroit différent. Cependant, chaque projet a ses spécificités et ce n’est pas toujours applicable. Mais, lorsque cela est possible, je trouve extrêmement pratique d’avoir une vue unifiée des conditions d’entrée, du sujet testé et de l’assertion de sortie. Tout en un seul endroit sans avoir à ouvrir un autre fichier.

Pour illustrer cela, nous utilisons le title-to-frontmatter package créé dans le premier article de cette série. Brièvement title-to-frontmatter analyse un document Markdown, en supprime le titre et le place à l’intérieur du frontmatter objet. Le code se trouve dans le ./packages/title-to-frontmatter annuaire.

Pour tester le module “./lib/index.js”, nous écrivons un test en test/index.js fichier utilisant à la fois Mocha et Should.js. L’épreuve ressemble à ça :

const Remark = require('remark')
const toHtml = require('hast-util-to-html')
const toHast = require('mdast-util-to-hast')
const extractTitle = require('..')

describe( 'Extract title', () => 

  it( 'Move the title to frontmatter', () => 
    
    const mast = (new Remark()).parse(
      [
        '# this is the title',
        'and some text'
      ].join('\n')
    )
    const frontmatter = 
    
    extractTitle(
      markdownNode: 
        frontmatter: frontmatter
      ,
      markdownAST: mast
    , )
    
    const hast = toHast(mast)
    const html = toHtml(hast)
    
    html.should.eql('<p>and some text</p>')
    frontmatter.should.eql(
      title: 'this is the title'
    )
  )
)

Avant d’exécuter le test, nous devons d’abord ajouter les dépendances nécessaires :

yarn add -D \
  remark \
  hast-util-to-html \
  mdast-util-to-hast

Une fois cela fait, nous pouvons exécuter notre test :

yarn mocha test/index.js
yarn run v1.22.5
$ /Users/david/projects/github/remark-gatsby-plugins/node_modules/.bin/mocha test/index.js

  Extract title
    ✓ Move the title to frontmatter

  1 passing (13ms)

✨  Done in 0.56s.

Le test a réussi. Nous sommes bons et prêts à nous engager :

git add package.json test/index.js
git commit -m "test(gatsby-remark-title-to-frontmatter): move the title to frontmatter"

Structure du projet avec tests

En règle générale, il est recommandé d’aligner la structure de votre dossier de test sur la structure de votre code source. Il existe principalement trois stratégies pour placer vos tests.

Certains développeurs incluent les tests directement à côté du code source. Les tests peuvent alors être exécutés sous certaines conditions comme avec la présence d’une certaine variable d’environnement ou lorsque le module est exécuté directement au lieu d’être requis.

Il est également possible de placer les tests à côté du module testé. En utilisant une convention de nommage comme ./lib/my_module.test.jsune expression globale similaire à node lib/**/*.test.* exécuter uniquement les tests unitaires.

Enfin, mon approche préférée, que j’ai utilisée ci-dessus, consiste à placer les tests dans un dossier dédié comme ./test. Le test ./test/my_module.js va tester le ./lib/my_module.js module. Si plusieurs aspects du module ont été testés, vous pouvez également placer plusieurs tests dans ce dossier nommé d’après votre module, par exemple à l’intérieur ./test/my_module.

Tests unitaires avec CoffeeScript

je préfère utiliser CoffeeScript lors de la rédaction de mes tests. C’est l’approche que j’ai adoptée pour le Analyseur CSV forfait. Le code source est écrit en JavaScript tandis que les tests sont en CoffeeScript. Cela rend le code des tests plus court et beaucoup plus expressif. Intégrons CoffeeScript et convertissons notre test :

A l’intérieur de la configuration Moka présente dans le package.json fichier, ajouter coffeescript/register:


  "mocha": 
    "throw-deprecation": true,
    "require": [
      "should",
      "coffeescript/register"    ],
    "inline-diffs": true,
    "timeout": 40000,
    "reporter": "spec",
    "recursive": true
  

Comme avec Should.js, CoffeeScript est enregistré dans Mocha. Ainsi, le code est automatiquement transpilé de CoffeeScript vers JavaScript avant d’être exécuté par le moteur Node.js. Maintenant, nous pouvons convertir notre code JavaScript en CoffeeScript :

Remark = require 'remark'
toHtml = require 'hast-util-to-html'
toHast = require 'mdast-util-to-hast'
extractTitle = require '..'

describe 'Extract title', ->

  it 'Move the title to frontmatter', ->
    
    mast = (new Remark()).parse """
    # this is the title
    and some text
    """
    frontmatter = 
    
    extractTitle
      markdownNode:
        frontmatter: frontmatter
      markdownAST: mast
    , 
    
    hast = toHast mast
    html = toHtml hast
    
    html.should.eql '<p>and some text</p>'
    frontmatter.should.eql
      title: 'this is the title'

je laisse la comparaison avec l’original test/index.js fichier à votre jugement, nous avons tous des goûts différents. Pour exécuter tous les tests, nous pouvons maintenant enregistrer le yarn test commande à l’intérieur du package.json dossier de notre title-to-frontmatter forfait. En supposant que les tests sont écrits en CoffeeScript (sinon, changez le .coffee extension à .js dans l’expression globale), la commande doit ressembler à ceci :


  "scripts": 
    "test": "mocha 'test/**/*.coffee'"
  

Exécution de la yarn test (ou npm test) produit la même sortie qu’avec la commande mocha commande:

yarn test
yarn run v1.22.5
$ mocha 'test/**/*.coffee'

  Extract title
    ✓ Move the title to frontmatter

  1 passing (11ms)

✨  Done in 0.83s.

Tout va bien, nous pouvons maintenant valider nos modifications :

git rm test/index.js
git add package.json test/index.coffee
git commit -m "test(gatsby-remark-title-to-frontmatter): convert test to coffee"

Tirer parti lerna pour les tests unitaires

Jusqu’à présent, nous venons de montrer comment exécuter les tests dans un seul package. Naviguer dans chaque package pour exécuter chaque test prend du temps et est sujet aux erreurs, en particulier si votre monorepos est composé de nombreux packages. En s’appuyant sur Lerna, une seule commande est utilisée pour exécuter tous les tests à l’aide du lerna run commande:

lerna run <script> -- [...args]

Cette commande exécute un script NPM dans chaque package contenant ce script. Comme indiqué précédemment, notre package contient un script NPM alias pour test dans son package.json dossier:


  ...
  "scripts": 
    "test": "mocha 'test/**/*.coffee'"
  

Par conséquent, l’exécution de la commande suivante devrait exécuter tous les tests :

lerna run test
info cli using local version of lerna
lerna notice cli v3.22.1
lerna info versioning independent
lerna info Executing command in 1 package: "yarn run test"
lerna info run Ran npm script 'test' in 'gatsby-remark-title-to-frontmatte
r' in 0.5s:
yarn run v1.22.10
$ mocha 'test/**/*.coffee'


  Extract title
    ✓ Move the title to frontmatter


  1 passing (8ms)

Done in 0.41s.
lerna success run Ran npm script 'test' in 1 package in 0.5s:
lerna success - gatsby-remark-title-to-frontmatter

Comme vous pouvez le voir dans la sortie de la commande, le mocha 'test/**/*.coffee' a été exécuté dans notre package testé. À juste titre, plus vous aurez de packages et de tests et plus vous aurez de scripts lerna s’exécutera.

Nous pouvons maintenant faire une chose de plus pour peaufiner notre approche. Pour éviter d’entrer dans lerna commande à chaque fois, nous pouvons modifier la package.json trouvé dans la racine de notre monorepos comme suit :


  "scripts": 
    "postinstall": "husky install",
    "publish": "lerna publish from-git --yes",
    "test": "lerna run test"  

Après avoir aliasé notre "test" scénario avec "lerna run test"nous utilisons le yarn test commande pour exécuter nos tests.

Aide-mémoire

  • Installez Mocha et Should.js :
    yarn add -D mocha should
    
    yarn add -D coffeescript
  • Configuration moka à l’intérieur package.json:
    
      "mocha": 
        "throw-deprecation": true,
        "require": [
          "should",
          "coffeescript/register"
        ],
        "inline-diffs": true,
        "timeout": 40000,
        "reporter": "spec",
        "recursive": true
      
    
  • Modèle moka en JavaScript :
    describe( 'Group description', () => 
      it( 'Test description', () => 
        
      )
    )
  • Modèle Moka dans Coffee :
    describe 'Group description', ->
      it 'Test description', ->
        
  • Enregistrez un test scénario dans package.json:
    
      "scripts": 
        "test": "mocha 'test/**/*.coffee'"
      
    
  • Enregistrez un test script pour exécuter des tests à partir de tous les packages avec Lerna :
    
      "scripts": 
        "test": "lerna run test"
      
    

Conclusion

Nous avons brièvement parlé de quelques bonnes pratiques lors de l’utilisation des tests unitaires avec Moka cadre et Devrait.js. Nous avons montré comment écrire des tests à la fois en JavaScript et en CoffeeScript. Ce dernier n’a demandé qu’à ajouter le package approprié et à configurer Mocha pour l’utiliser dans le package.json dossier. Hormis quelques différences esthétiques et d’expressivité entre JavaScript et CoffeeScript, les tests d’écriture restent similaires dans les deux langages. Cependant, j’apprécie l’expressivité et la lisibilité de CoffeeScript et en tant que tel, il reste mon langage de prédilection pour la rédaction de tests. Enfin, gardez à l’esprit que l’écriture et la configuration de tests unitaires dans monorepos ne sont pas différentes des référentiels classiques. Assurez-vous simplement que chaque dossier de test reste dans le bon package et exploitez le lerna run commande pour exécuter les tests présents dans tous vos packages.

Dans notre prochain article, nous verrons que si la mise en œuvre de tests dans monorepos est assez facile, l’intégration du pipeline CI/CD pour automatiser la publication de packages nécessite quelques paramètres supplémentaires, qui seront largement couverts.

Leave a Reply