← Journal technique

devops

Un kit de tests qui ne dépend pas de la stack

Un kit de tests qui ne dépend pas de la stack

Les tests d'EduQate ont fini en cinq workflows CI : back-end, front-end, E2E navigateur, hygiène et sécurité, et une exécution planifiée chaque semaine. Je ne travaille pas qu'en Node, et je voulais le même filet de sécurité sur un projet .NET ou Rust sans tout refaire à la main. J'ai donc sorti la structure dans un kit.

Trois couches, une seule dépend de la stack

  1. Un adaptateur de stack — un petit Makefile par stack (node.mk, dotnet.mk, rust.mk, nextjs.mk, angular.mk). Il associe chaque type de test à la commande qui le lance : unit, c'est Jest sur Node, dotnet test --filter Category=Unit sur .NET, cargo test --lib sur Rust.
  2. Un Makefile aux cibles fixes — unit, api, db, races, cache, sec, smoke, etc. La CI n'appelle que make <cible>, donc les workflows ne changent pas quand la stack change. Une cible sans commande pour cette stack affiche [skip] au lieu d'échouer.
  3. Des tests indépendants de la stack — Playwright, k6, tests de fumée, CodeQL, Trivy, actionlint. Ils parlent à un système en marche via HTTP, donc ils fonctionnent pareil contre Node, .NET ou Rust.

Un dépôt mixte choisit une stack par workflow : .NET pour le workflow back-end, Angular pour le front-end.

Le dossier N tourne dans le workflow N

# Workflow Contenu
1 Back-end et services unitaires, intégration API avec une matrice route × rôle, vrai Postgres, tests de concurrence, vrai Redis, sûreté des migrations, un test de non-régression par bug, specs de sécurité, démarrage à froid
2 Applications front-end paquets partagés, lint, tests de composants, build, mobile
3 E2E navigateur un parcours par rôle, une matrice d'accès, doubles soumissions, états vides, i18n et RTL, 2FA, contrôles d'accessibilité axe, captures de référence
4 Hygiène et sécurité lint des tests, actionlint, vérification de la config du reverse proxy, CodeQL, Trivy
5 Planifié tests de mutation, charge k6, sauvegarde puis restauration

Numéroter les dossiers d'après les workflows paraît anodin. C'est ce qui me permet de trouver « où est le test de concurrence pour X » sans réfléchir.

Les règles qui vont avec

  • Fini veut dire vu en marche. Un changement visible à l'exécution est fini quand je l'ai utilisé dans l'application en marche sans nouvelle erreur console ou réseau, pas quand il compile.
  • De vraies dépendances là où vivent les bugs. Mocker le prestataire de paiement et le service d'e-mail, oui. Mocker sa propre base, son cache ou sa pile HTTP dans les tests d'intégration, non : un test mocké est d'accord avec le code, pas avec la réalité.
  • Chaque bug devient un test, nommé d'après son identifiant dans le registre des problèmes, et jamais supprimé.
  • La sécurité est un test, pas une relecture. Accès anonyme, mauvais rôle, un utilisateur qui lit la fiche d'un autre, limites de débit et recherche de secrets tournent tous en CI.
  • Les exécutions lourdes vont en CI. Couverture, mutation et tests de charge sont lents et gourmands. Ils n'ont rien à faire sur un portable.
  • Un test instable est un bug. Attendre le vrai signal plutôt qu'un délai, donner à chaque test ses propres données, ou le mettre en quarantaine au vu de tous. Jamais relancer jusqu'au vert.

Le faire grandir dans un nouveau projet

D'abord un test de fumée et un test unitaire, pour une CI verte dès le premier jour. Ensuite les tests API sur l'authentification et le flux principal, puis la matrice d'accès et les specs de sécurité. Les tests de base, de concurrence et de migrations arrivent dès qu'il y a de vraies données. Puis un parcours Playwright par rôle. Les captures de référence attendent que l'interface se stabilise. Mutation, charge et restauration de sauvegarde sont en place avant le lancement.