#! TDD en Bash

(Serious business)

Michael Borde / @michael_borde / Arpinum

Arpinum

Le contexte

JLA
© DC Comics

Quelques chiffres

  • 119 entrepôts
  • 2,3 Millions de lignes de Java
  • 282 projets Maven
  • 4566 commits / mois
  • 52 auteurs actifs

Retournons quelques temps en arrière...

L'ère ClearCase

Monsieur Lent
© Roger Hargreaves

Puis l'ère du possible avec Git

Sharknado
© Sharknado

Et si nous automatisions les opérations répétitives et sensibles ?

Un outil simple : Bash

3 fois rien finalement

  • Cloner des entrepôts
  • Mettre à jour des sources

Mais avec un peu d'imagination

  • Créer/supprimer des branches
  • Créer/supprimer des jobs Jenkins
  • Lister les entrepôts à fusionner
  • Réaliser la livraison des projets
  • etc.

18 vaillants scripts

Et il y en a pour tout le monde

Equipe développement

Développeurs, administrateurs, livreurs, etc.

Dans des contextes multiples

Logo Cygwin Logo Jenkins Logo Linux

avec un mode de tests manuels, mais chut!

Deux exemples


./execute -p "*reference*" -y jar -b integration "mvn clean install"

./assigne-version -c auto "3.4.2-SNAPSHOT"
          

Les conseils de Google

If you are writing a script that is more than 100 lines long, you should probably be writing it in Python instead.

En Python !

Dawson triste
© Toute la production de Dawson's Creek

Eh oui, scripter en Bash c'est un peu...

Dé Stackoverflow Necronomicon

Un exemple de Bash

https://github.com/creationix/nvm

(Node Version Manager - Simple bash script to manage multiple active node.js versions)

Nous avons 4796 lignes de Bash !

Panneau stop

Il faut tacler la complexité

Et si Bash était un langage de programmation ?

Les outils habituels

TDD By Example XP Explained Clean Code

Clean Code, concrètement ?

Un équivalent à JUnit ?

JUnit

Bof...

Je vais créer mon api de tests automatisés en Bash !

Serious cat

Une si bonne idée...

Les objectifs de l'api

  • Favoriser TDD
  • Ressembler à xUnit
  • Compatible avec l'IC
  • Respecter la notion de tests unitaires
  • En français

Make them first

  • Fast
  • Isolated !
  • Repeatable !
  • Self-verifying !
  • Timely

Et donc ?

L'exécuteur de test

Exécuter tous les fichiers de test


function executeur_executeLesFichiersDeTestDansLeRepertoire() {
  local repertoire="$1"
  _initialiseLExecutionDesTests
  _executeTousFichiersDeTest "${repertoire}" "*Test.sh"
  _afficheLeResultatDesTests
  _retourneUnCodeEnFonctionDuResultatDesTests
}
          

Exécuter un fichier de test


function _executeLeFichierDeTest() {
  local fichier="$1"
  source "${fichier}"
  local fonctions=("$(_fonctionsPubliquesDansLeFichier "${fichier}")")
  _executeFonctionSiPresente "avantTousLesTests" "${fonctions[@]}"
  _executeTousLesTests "${fonctions[@]}"
  _executeFonctionSiPresente "apresTousLesTests" "${fonctions[@]}"
}
          

Exécuter une fonction de test


function _executeLaFonctionAuMilieuDuSetupEtTeardown() {
  local fonction="$1"
  shift 1
  _executeFonctionSiPresente "avantChaqueTest" "$@" \
  && ${fonction} \
  && _executeFonctionSiPresente "apresChaqueTest" "$@"
  _analyseLExecutionDuTest "${fonction}" $?
}
          

Quelques affirmations

Affirmer l'égalité


function affirmation_affirmeEgalite() {
  local attendu="$1"
  local obtenu="$2"
  if [[ "${attendu}" != "${obtenu}" ]]; then
    _affirmationEnErreur "Obtenu : ${obtenu}, attendu : ${attendu}."
  fi
}
          

Affirmer le succès


function affirmation_affirmeSucces() {
  ( $@ )
  if (( $? != 0 )); then
    _affirmationEnErreur "La commande a échoué au lieu de réussir."
  fi
}
          

Quelques exemples

Un test unitaire


function recupereBienLaVersionDunPom() {
  local pom="${_ressources}/pom_1.0.xml"

  local version="$(maven_recupereLaVersionDuPom "${pom}")"

  affirmation_affirmeEgalite "1.0" "${version}"
}
          

Un test d'intégration


function ilEstPossibleDeChangerLaBrancheDUnEntrepot() {
  entrepot_cloneLaBrancheDeLEntrepot "integration" "module-a"

  source "${REPERTOIRE_SCRIPT}/checkout" -p "mod*" "master"

  local branche="$(_recupereLaBrancheCouranteDeLEntrepot "module-a")"
  affirmation_affirmeEgalite "master" "${branche}"
}
          
Résultat tests
Exemple de sortie console

Reprenons les statistiques

Lignes %
Production 2797 58%
Tests 1671 35%
API de tests 328 7%
Total 4796 100%

Et pour le fun

Nombre Temps
Tests unitaires 91 13 s
Tests d'intégration 109 10 min

Et ensuite?

... ensuite naquit shebang_unit.
http://github.com/arpinum/shebang_unit

Pour finir

  • Qualité ❤
  • DIY !
  • Du fun, plein

Fin