Vous modifiez un pipeline de chargement client pour ajouter une règle de normalisation des codes postaux. Le pipeline se lance, les compteurs sont verts, aucune erreur ne remonte. Trois jours plus tard, quelqu’un s’aperçoit que les enregistrements sans pays ne sont plus rejetés mais silencieusement affectés à la France. Le pipeline n’avait rien signalé : il faisait exactement ce que vous lui aviez demandé, mais pas ce que vous vouliez.

Le réflexe habituel consiste à relancer le pipeline sur un extrait de production et à regarder le résultat à l’œil nu. Cette vérification ne laisse aucune trace, ne se rejoue pas, et devient impraticable dès que le pipeline dépasse une dizaine de transforms. Apache Hop propose une alternative intégrée : un framework de tests unitaires qui remplace vos sources par des données figées et compare la sortie à un résultat de référence. Cet article vous montre comment le mettre en place.

Prérequis

1. Les trois objets qui composent un test

Hop ne réutilise pas un framework externe. Il expose trois types de métadonnées dédiés, que vous retrouverez dans l’arborescence Metadata de Hop Gui :

Type de métadonnée Rôle
Data Set Une collection de lignes statique, stockée en CSV, décrite par une liste de champs typés. Elle sert soit d’entrée injectée dans le pipeline, soit de résultat attendu.
Pipeline Unit Test L’assemblage : quel pipeline est testé, quels data sets alimentent quels transforms, quel data set sert de référence, quelles variables sont positionnées.
Unit Test Tweak Une modification appliquée au pipeline pendant le test uniquement : contourner ou supprimer un transform.

Le principe est simple à retenir : pendant l’exécution du test, Hop travaille sur une copie en mémoire du pipeline. Les transforms auxquels vous avez associé un jeu de données d’entrée sont remplacés par un transform Injector qui débite les lignes du CSV. Votre pipeline de production n’est jamais modifié, et aucune base de données n’est sollicitée.

2. Préparer le projet

Trois propriétés du projet déterminent où tout cela atterrit. Vous les trouvez dans la boîte de dialogue du projet :

Propriété Valeur par défaut Variable
Metadata base folder ${PROJECT_HOME}/metadata —
Data Sets CSV Folder ${PROJECT_HOME}/datasets HOP_DATASETS_FOLDER
Unit Test Base Path ${PROJECT_HOME} HOP_UNIT_TESTS_FOLDER

Laisser ces valeurs par défaut présente un avantage décisif : les définitions de tests et les fichiers CSV vivent dans le dossier du projet, donc dans le même dépôt Git que vos pipelines. Un test arrive avec la modification qu’il valide, et une revue de code montre les deux côte à côte.

3. Créer le test et son jeu de données d’entrée

Ouvrez le pipeline à tester dans Hop Gui. La barre d’outils de test unitaire propose une icône + qui crée un nouveau test. La boîte de dialogue demande notamment :

Le test existe, il lui faut maintenant des données. Faites un clic droit sur le transform d’entrée de votre pipeline — celui qui lit la table ou le fichier source — puis :

  1. Create data set : Hop déduit la structure du jeu de données à partir des champs qui sortent du transform.
  2. Write rows to data set : exécutez le pipeline une fois pour capturer des lignes réelles et les figer dans le CSV.
  3. Set input data set : associez ce jeu de données au transform, pour ce test.

Ouvrez ensuite le CSV et réduisez-le. Un bon jeu d’entrée tient en quelques dizaines de lignes choisies : le cas nominal, les cas limites, et précisément les lignes qui ont provoqué l’incident que vous corrigez. Dix mille lignes de production ne testent rien de plus et rendent tout diagnostic pénible.

4. Définir le résultat attendu

La démarche est symétrique côté sortie. Clic droit sur le transform final, puis Create data set, Write rows to data set pour capturer la sortie de référence, et enfin Set golden data set.

Attention à l’ordre des opérations : ne capturez la golden data qu’à partir d’un pipeline dont vous avez vérifié le comportement. Sinon vous figez un bug et le test défendra désormais ce bug contre toute correction. La bonne pratique consiste à relire le CSV de référence ligne à ligne la première fois — c’est fastidieux une fois, jamais plus ensuite.

À l’exécution, Hop compare la sortie réelle au contenu du jeu de référence. En cas de succès, le journal affiche Test passed succesfully against golden data set. En cas d’échec, une fenêtre détaille les écarts : nombre de lignes, champs dont la valeur diffère.

5. Neutraliser ce qui n’a pas à être testé

Un pipeline contient souvent des transforms qu’il serait absurde de déclencher pendant un test : une écriture en base, un envoi de courriel, un appel à un service payant. Le clic droit sur le transform propose deux options :

Ces modifications s’affichent sous forme de marqueurs visuels sur les icônes des transforms concernés, ce qui évite de se demander plus tard pourquoi le test ne charge rien.

6. Rejouer les tests hors de l’interface

Un test que l’on ne lance qu’en cliquant dans Hop Gui ne protège de rien. Hop offre trois mécanismes pour automatiser l’exécution.

L’action de workflow Run pipeline unit tests exécute une liste de tests et échoue si l’un d’eux échoue. Son bouton Get test names récupère les tests disponibles dans le projet courant. Placez cette action dans un workflow tests.hwf, et vous disposez d’un point d’entrée unique.

Le transform Execute unit tests fait le même travail à l’intérieur d’un pipeline, mais renvoie un flux de lignes exploitable. Ses champs de sortie sont configurables et couvrent le pipeline testé, le test exécuté, le data set utilisé, le transform concerné, un statut d’erreur (Y ou N) et un commentaire. C’est la voie à suivre si vous voulez historiser les résultats dans une table ou produire un rapport.

La ligne de commande enfin, avec hop-run, qui est ce que votre serveur d’intégration continue appellera :

hop-run.sh \
  --project=mon-projet \
  --environment=dev \
  --runconfig=local \
  --file=${PROJECT_HOME}/tests.hwf \
  --level=BASIC \
  --logfile=/var/log/hop/tests.log

Les options utiles ici sont -j / --project, -e / --environment, -r / --runconfig, -f / --file, -l / --level et -lf / --logfile. Vous pouvez également passer des paramètres avec -p PARAM=VALEUR, en séparant les couples par des virgules, ou par un autre caractère via -ps.

Le code de retour du processus reflète le succès ou l’échec du workflow : c’est lui que votre job d’intégration continue doit surveiller.

7. Par où commencer

Tester l’intégralité d’un patrimoine existant est un projet en soi, et ce n’est pas ce qu’il faut viser. Une approche réaliste :

  1. Choisissez le pipeline qui vous a déjà coûté un incident. Écrivez son test aujourd’hui.
  2. Ajoutez un test à chaque correction de bug, en capturant d’abord un jeu d’entrée qui reproduit le problème.
  3. Regroupez les tests dans un workflow unique et faites-le tourner à chaque livraison.

Ce que vous y gagnez

Vous disposez maintenant d’un moyen de modifier un pipeline sans compter sur votre mémoire pour savoir ce qu’il produisait avant. Les jeux de données d’entrée et de référence sont versionnés avec les pipelines, ce qui rend une revue de code lisible : on voit la règle qui change et l’exemple qui la démontre. Et parce que tout s’exécute depuis hop-run, ces vérifications peuvent quitter votre poste pour devenir une étape de votre chaîne de livraison — sujet auquel nous consacrerons un prochain article.

Pour aller plus loin

Un projet Apache Hop ? Parlons-en.

Devis et programme détaillé sous 48 h ouvrées. Financement OPCO accompagné.

Demander un devis