Les bonnes pratiques des tests dans un environnement CI/CD

28 Août 2023

Introduction

L'intégration continue / déploiement continu (CI/CD) permet de compiler, tester et déployer son code d'une manière automatisée. Après avoir passé l'étape de la compilation, le passage du code par plusieurs phases de tests automatisés permet de vérifier si l'application se comporte comme prévu, que le code nouvellement introduit n'est pas source de régressions sur tout ce qui a déjà été livré en production durant la version précédente et que l'ensemble répond aux normes en ce qui concerne la qualité et la maintenabilité. Les tests prennent donc une grande importance dans le processus de développement de l'application ; ils garantissent que le programme fait réellement ce qu'il est censé faire, assurent sa stabilité et que le code respecte les normes et la qualité.

Les tests automatisés auxquelles sera soumise une application dans un environnement CI/CD peuvent prendre plusieurs formes :

La vérification de la qualité du code

La vérification de la qualité du code s'intéresse à des problèmes concernant la performance, le style, la complexité et la présence de structures de codes qui peuvent représenter un risque élevé de bugs. Elle peut remonter plusieurs types d'erreurs sur la qualité du code livré :

Implémentation sur un projet Symfony

Avec des projets en PHP sous Symfony, plusieurs outils peuvent être utilisés pour vérifier la qualité du code :

Exemple en utilisant Psalm

PSalm est un des outils qui permettent de vérifier la qualité du code.
La configuration d'un pipeline sur GitLab dans un fichier .gitlab-ci.yml pour vérifier automatiquement la qualité du code Symfony en utilisant PSalm peut se présenter comme suit :

.gitlab-ci.yml :
    stages:
        - test

    psalm:
        stage: test
        image: php:8.2.8-cli-bullseye
        before_script:
            # Install and configure php extensions
            - chmod +x ./.scripts/configure-php.sh && ./.scripts/configure-php.sh
            # Install projects dependencies
            - composer install
            # Install Psalm
            - composer require --dev vimeo/psalm
        script:
            - ./vendor/bin/psalm
Code Symfony contenant une variable non utilisée :

Prenons un code Symfony contenant la variable $request non utilisée :

symfony_code.png

Erreur détectée sur GitLab :

psalm_error.png

Les tests unitaires

Les tests unitaires ont pour objectif d'éliminer les risques de bugs dans le code. Les tests unitaires vont découper l'ensemble du code en composants ou unités individuelles de manière isolés et voir si chacune d'elles fonctionnent correctement. Pour ce faire, des codes de test vont être écrits sur chaque fonction présente dans l'ensemble de l'application. Les tests unitaires vont prendre une petite unité de l’application, généralement une méthode, l’isoler du reste du code et vérifier qu’elle se comporte comme prévu.

À chaque écriture d'une fonction ou un autre bloc de code d’application, des tests unitaires sont créés pour vérifier le comportement du code en réponse aux cas standard, limites et incorrects des données d’entrée, ainsi que les hypothèses explicites ou implicites du code. Les tests unitaires peuvent ainsi devenir une documentation de conception et de spécifications fonctionnelles.

Chaque modification apportée nécessite la ré-exécution des tests unitaires pour vérifier que le code fonctionne toujours correctement. L'automatisation du lancement des tests unitaires dans un environnement CI/CD va faire passer les series de tests pour voir si d'une manière isolée tout fonctionne comme prévu et ainsi remonter les erreurs en cas d'échec. Cela va permettre d'assurer que le fonctionnement de chaque module répond aux spécifications avant la livraison vers l'environnement de production.

Implémentation avec Javascript et NestJS

Le framework NestJS embarque par défaut le framework javascript de test JEST.

La configuration d'un pipeline sur GitLab dans un fichier .gitlab-ci.yml pour lancer les tests unitaires sur un projet NestJS en utilisant JEST peut se présenter comme suit :

.gitlab-ci.yml :
    stages:
      - test

    jest:
      stage: test
      image: node:18.16.1
      before_script:
        - npm install
      script:
        - npm run test
Code d'un test unitaire NestJS :

Prenons un code de test pour une fonction sumNumber qui doit retourner la somme de 2 nombres :

nest_test

Code du service NestJS :

Prenons un code d'un Service NestJS ayant une fonction sumNumber qui retourne une mauvaise valeur :

nest_function.png

Résultat du lancement des tests unitaires sur gitlab :

jest_error.png

Les tests fonctionnels

Là où les tests unitaires faisaient des validations du point de vue des programmeurs et sont généralement spécifiés par l'équipe de développement, les tests fonctionnels vont se concentrer sur la validation des fonctionnalités de l'application du point de vue de l'utilisateur final. Pour déterminer si l'application répond aux besoins fondamentaux de l'utilisateur final, les tests fonctionnels vont garantir que chaque fonctionnalité de l'application fonctionne conformément aux exigences sans s'intéresser à la manière dont le traitement est effectué. Les tests fonctionnels se focalisent ainsi sur la question de savoir si le traitement fournit les bons résultats ou s'il présente des bugs.

Implémentation avec Angular et Cypress

Cypress fait partie des outils permettant de créer facilement des tests fonctionnels pour les applications web utilisant les frameworks modernes actuels tels que Angular ou React.

La configuration d'un pipeline sur GitLab dans un fichier .gitlab-ci.yml pour lancer les tests fonctionnels sur un projet Angular en utilisant Cypress peut se présenter comme suit :

.gitlab-ci.yml :

    stages:
      - test

    cypress:
      image: node:18.16.1
      stage: test
      before_script:
        - apt-get update
        - apt-get install -y libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb
        - npm install -g @angular/cli@16.1.5
        - npm install
      script:
        # start the server in the background
        - npm run start &
        # run Cypress tests
        - npm run cypress:run

Code de tests fonctionnels en Cypress

cypress_test.png

Code de routing dans le projet en Angular

angular_routing.png

Erreur soulevée lors du lancement des tests fonctionnels sur gitlab :

cypress_error.png

Pour finir

Les différents types de tests évoqués touchent différents aspects de l'application. La mise en place de ces tests dans un environnement CI/CD va permettre de réduire le risque de livraison de codes défectueux en automatisant la détection des erreurs et des bugs, la vérification de la qualité, le bon fonctionnement et la fiabilité de l'application. Le déclenchement de ces tests à chaque modification du code va permettre de recevoir des feedbacks rapides sur la qualité et la performance de vos applications. L'objectif final est ainsi d'améliorer grandement la qualité de l'application livrée et la satisfaction des utilisateurs finaux.

top