Objectifs
- Comprendre pourquoi il est important de tester ses scripts shell.
- Découvrir un framework de test simple comme
bats-core. - Écrire un premier test qui vérifie le code de sortie et la sortie d’un script.
- Intégrer les tests dans un processus de validation automatisé (CI).
Explications détaillées
Notions clés
Tester manuellement un script est répétitif et source d’erreurs. Les tests automatisés garantissent que votre script se comporte comme prévu et que des modifications futures ne cassent pas une fonctionnalité existante (non-régression).
bats-core : Un framework de test pour Bash
bats-core (Bash Automated Testing System) est un framework populaire qui apporte une structure de type “TAP” (Test Anything Protocol) à vos tests shell. Il permet d’écrire des tests de manière lisible et structurée.
Un fichier de test bats est un script Bash avec une syntaxe spéciale :
- Les tests sont des fonctions préfixées par
@test "description". - À l’intérieur, vous exécutez la commande ou le script que vous voulez tester.
batsfournit des variables spéciales comme$status(le code de sortie) et$output(la sortie standard) de la dernière commande exécutée avecrun.
Assertions : Vérifier les résultats
Un test “réussit” si toutes ses commandes se terminent avec un code de sortie 0. On vérifie les résultats avec des conditions [[ ... ]].
[[ "$status" -eq 0 ]]: La commande a-t-elle réussi ?[[ "$output" == "Hello" ]]: La sortie est-elle exactement “Hello” ?
Golden Files
Pour tester une sortie complexe, au lieu de la mettre en dur dans le script de test, on la stocke dans un fichier de référence (“golden file”). Le test consiste alors à comparer la sortie actuelle avec le contenu de ce fichier.
Syntaxe / Usages
# Installation de bats-core (par exemple via npm ou clonage du repo)
# npm install -g bats
# Exemple de fichier de test : test/mon_script.bats
#!/usr/bin/env bats
# 'load' permet d'inclure des fichiers de helper, comme la librairie d'assertions
load 'test_helper/bats-support/load'
load 'test_helper/bats-assert/load'
@test "mon_script.sh doit afficher Bonjour" {
# 'run' exécute la commande et capture $status et $output
run ./mon_script.sh
assert_success # Vérifie que $status est 0
assert_output "Bonjour"
}
@test "mon_script.sh avec un argument" {
run ./mon_script.sh "Alice"
assert_success
assert_output "Bonjour, Alice"
}
# Pour lancer les tests
# bats test/
Exemples
Supposons un script calcul.sh :
#!/bin/bash
if [[ $# -ne 2 ]]; then exit 1; fi
echo $(($1 + $2))
Le fichier de test test/calcul.bats pourrait être :
#!/usr/bin/env bats
load 'test_helper/bats-support/load'
load 'test_helper/bats-assert/load'
@test "calcul.sh additionne 2 et 3" {
run ./calcul.sh 2 3
assert_success
assert_output "5"
}
@test "calcul.sh doit échouer sans arguments" {
run ./calcul.sh
assert_failure # Vérifie que le code de sortie est non-nul
}
Bonnes pratiques
- Un test par comportement. Chaque fonction
@testne doit vérifier qu’une seule chose. - Nommez vos tests clairement. La description doit expliquer ce que le test vérifie.
- Intégrez les tests à votre CI/CD. Lancez
batsautomatiquement à chaquepushoupull request.
Pièges courants
- Dépendances à l’environnement : Un test qui dépend d’un fichier ou d’une variable d’environnement spécifique peut échouer sur une autre machine. Utilisez des
setupetteardownpour créer un environnement de test propre. - Sorties complexes : Tester une sortie HTML ou JSON complexe avec
assert_outputest fragile. Préférez les “golden files”.
Exercices
-
Installez
bats-core:- Suivez les instructions sur le dépôt GitHub de
bats-corepour l’installer.
- Suivez les instructions sur le dépôt GitHub de
-
Testez un script simple :
- Créez un script
hello.shqui affiche “Hello World”. - Créez un fichier
test/hello.batsqui vérifie que le script réussit et que sa sortie est bien “Hello World”. - Lancez
bats test/.
- Créez un script
-
Testez les cas d’erreur :
- Modifiez
hello.shpour qu’il prenne un nom en argument et qu’il quitte avec une erreur s’il n’y en a pas. - Ajoutez un test dans
hello.batsqui vérifie que le script échoue (assert_failure) lorsqu’il est appelé sans argument.
- Modifiez