Comment organiser ses tests E2E en architecture Micro-Service

Optimisez vos tests E2E en architecture micro-services : comment rapatrier les mocks à leur service d'origine pour des tests plus fiables et maintenir la cohérence API.
Tout d'abord, laissez-moi vous donner un peu de contexte concernant mon point de vue sur les architectures micro-services. Je développe depuis presque 17 ans en environnement professionnel, j'ai passé énormément de temps sur des projets (monolitiques ou micro-services). Depuis presque 7 ans, le micro-service est mon quotidien de développeur, ayant travaillé sur des projets à grande échelle, dans une filiale de TripAdvisor, chez Engie ou chez Webedia. J'ai eu le temps de me familiariser avec cette architecture, voici un conseil ou une observation qui pourra vous faire gagner beaucoup de temps et d'argent.
Lorsque l'on découpe un projet en micro-services, le plus souvent on va donner à chacun de ces services un domaine métier. Sa responsabilité sera de gérer la couche data et logique de cette brique métier.
Par exemple: un service Users va gérer les utilisateurs, la persistance de ces derniers etc., de même pour un service Products, il va gérer les produits et leur persistance etc.
Lorsque l'on travaille en micro-services, on va souvent avoir des processus qui sont cross-services, une opération va débuter sur une brique puis finir sur une autre. Peu importe qu'on utilise un orchestrateur, une message-queue ou autre, il faut parcourir toute la chaîne.
Dans ce cas, les développeurs mettent souvent en place des tests e2e à partir d'outils comme Jest, Playwright ou Cucumber qui sont censés dérouler le workflow d'un bout à l'autre.
Pour ce faire, on s'appuie souvent sur des mocks lors de ces processus. Rares sont ceux qui font réellement du test de bout en bout avec la base de test, des jeux de données (fixtures) dédiés à ces mêmes tests etc.
Et mocker chaque service depuis une autre brique peut amener plusieurs problèmes:
- Un état faux comparé au service réel car un mock est un état statique qui peut rapidement devenir obsolète (dès que le service est mis à jour).
- Des tests positifs alors qu'ils devraient être en erreur.
- Ceci engendre une détection tardive des bugs.
- Incohérence entre les environnements.
- Connaissance fragmentée (les développeurs manipulent des éléments dont ils ignorent la logique métier complète s'ils ne sont pas owners).
L'ownership du mock
De la même manière qu'on a réparti les domaines métier dans des briques, la responsabilité du mock devrait revenir à la brique owner de ce domaine. C'est-à-dire qu'il n'y a aucun sens à ce que le mock Users se trouve dans une brique Products et vice-versa.
Pourquoi faut-il rapatrier les mocks et fixtures dans leur domaine respectif ?
La réponse est très simple, lorsque l'on met à jour une brique, on va rarement aller chercher dans toutes les autres où sont les dépendances et où on doit impacter les modifications afin que toute la chaîne reste d'équerre.
Lorsque l'on intervient sur une brique, admettons que ce soit Users, on va devoir passer les tests au moins sur cette brique, le linter, la compilation TypeScript etc. Ce qui signifie que c'est l'endroit idéal pour y mettre les mocks et fixtures car ces derniers seront mis à jour (par obligation) car ils ne respecteraient plus les règles de typage.
Comment propager ces changements ?
Je pense que chaque micro-service devrait fournir un endpoint /api/tests/... qui fournirait des endpoints de tests sur des features. Quitte à renvoyer des données statiques (fixtures).
Ce path devrait être le miroir de tous les autres paths de /api/...
Les équipes pourront choisir d'interagir ou non avec une vraie base mais cela permettrait d'avoir des tests avec un jeu de données à jour dans 100% des cas.
Quid de la production
En production il ne nous reste plus qu'à mettre un middleware 404 sur les paths /api/tests/... en fonction d'une condition sur NODE_ENV.
Mais ceci nous permettrait d'avoir des environnements de Staging ou UAT bien plus robustes et permettra de détecter des bugs bien plus tôt.
Aujourd'hui, lorsque l'on déploie une mise à jour sur une brique unique, on oublie souvent que cela impacte les autres projets et de nombreux edge bugs se produisent dans ces cas.
La CI pourrait alors redéclencher une chaîne de tests complète, cross-service et empêcher ce scénario catastrophe.

Alexandre P.
Développeur passionné depuis plus de 20 ans, j'ai une appétence particulière pour les défis techniques et changer de technologie ne me fait pas froid aux yeux.
Poursuivre la lecture dans la rubrique Dev