Résumé rapide

La capture et la relecture du trafic améliorent la précision des tests sandbox en remplaçant les simulations écrites manuellement par de véritables données de requête-réponse enregistrées à partir d’environnements de test. Cela permet d’éviter l’obsolescence des appareils, de garantir que les tests reflètent le comportement actuel de l’API et de capturer des structures de réponse complètes, y compris les champs inattendus et les formats d’erreur. Des outils comme Keploy identifient également automatiquement les champs non déterministes, rendant la relecture plus fiable.

Cette technique est particulièrement utile pour les intégrations d’API tierces, les microservices et les structures de réponse complexes. Cependant, il ne peut pas reproduire entièrement les données de production ou les charges de trafic réelles. La combinaison de la capture et de la relecture du trafic avec d’autres approches de test aide les équipes à détecter davantage de problèmes d’intégration dans le bac à sable avant qu’ils n’atteignent la production.

Introduction

L’écart entre un bac à sable et la production est toujours là. La question est de savoir quelle est sa largeur. Éloignez l’application de ses dépendances réelles et les tests s’exécutent rapidement et de manière fiable, sans appels réseau ni effets secondaires. C’est là le point. Le coût est que quelque chose doit remplacer ces dépendances – et tout ce qui les remplace a été écrit par quelqu’un qui a dû prédire ce que la véritable dépendance renverrait.

C’est cette prédiction qui introduit l’inexactitude. Pas l’isolement lui-même. L’écart entre la prédiction et la réalité. Lorsque cette différence compte – et c’est toujours le cas – le bac à sable ne parvient pas à résoudre le problème que la production va résoudre à la place.

La capture et la relecture du trafic réduisent cet écart sans abandonner l’isolement. Cela ne rend pas le bac à sable identique à la production. Rien n’y fait. Mais cela modifie la source des informations comportementales sur lesquelles l’environnement de test sandbox est construit, de la prédiction du développeur à la réalité observée. Ce changement a des effets spécifiques et mesurables sur la précision avec laquelle le bac à sable prédit ce que fera la production.

Pourquoi les approches standard Sandbox accumulent des imprécisions

Quelqu’un s’est assis et a écrit ce que le service de paiement renvoie en cas de paiement réussi. Puis j’ai écrit ce qu’il retourne pour une carte refusée. Ensuite, j’ai écrit le format d’erreur de délai d’attente. Ensuite, validez ces fichiers et passez au ticket suivant. C’était il y a huit mois. Le service de paiement a expédié quatorze fois depuis. Le véritable service de paiement continue de se déployer. Le test valide que l’application gère correctement cette réponse.

Cette approche présente un problème structurel qui ne concerne pas la qualité des connaissances du développeur. Il était temps.

La simulation est exacte lorsqu’elle est écrite. La véritable dépendance qu’elle représente ne cesse de changer. Les schémas API évoluent. Les formats de réponse aux erreurs sont mis à jour. De nouveaux champs apparaissent dans les réponses. Les anciens champs deviennent obsolètes. Six mois après les déploiements en amont, la simulation décrit un service qui a modifié son schéma d’erreur, renommé un champ et ajouté une nouvelle propriété de réponse obligatoire. Aucun de ces changements n’a déclenché d’alerte. Personne n’a envoyé de notification. Le fichier fictif se charge toujours proprement.

La plupart du temps, cette dérive reste cachée. La simulation renvoie toujours une réponse d’apparence valide. Les tests réussissent toujours. L’application se déploie toujours. La divergence n’apparaît que lorsque l’application rencontre la dépendance réelle en production et que la dépendance réelle renvoie quelque chose que l’application n’a pas été écrite pour gérer – parce que la simulation sur laquelle elle a été testée décrivait une ancienne version de ce comportement.

Dans les tests de logiciels, cela s’appelle l’obsolescence des appareils. Le correctif standard est un examen manuel – quelqu’un audite périodiquement les fichiers fictifs par rapport au comportement de dépendance actuel et met à jour ce qui a dérivé. En théorie, cela fonctionne. La pression de livraison et la simulation de maintenance ne coexistent pas confortablement. Le sprint se termine, la version est publiée, la simulation de révision est programmée pour la semaine prochaine. La semaine prochaine devient le prochain sprint. L’autopsie fait finalement ressortir le même résultat que celui de la plupart des autopsies sur l’obsolescence des appareils : l’écart était connu, la mise à jour n’a pas eu lieu et la production l’a trouvé en premier.

Ce que font différemment la capture et la relecture du trafic

Au lieu qu’un développeur écrive ce qu’il pense qu’une dépendance renvoie, la capture du trafic enregistre ce que la dépendance a réellement renvoyé au cours d’une session d’interaction réelle.

Lors de la capture, le trafic réseau de l’application passe par une couche intermédiaire qui enregistre chaque requête que l’application envoie à ses dépendances et chaque réponse renvoyée par ces dépendances. Cela se produit dans un environnement réel (généralement en environnement intermédiaire, où de vrais services s’exécutent et où de véritables interactions peuvent se produire) et non pas en production, ni pendant l’exécution normale des tests.

Après la session de capture, les paires requête-réponse enregistrées deviennent les éléments du bac à sable. Lorsque l’application appelle une dépendance lors d’exécutions de tests ultérieures, le bac à sable relit la réponse capturée au lieu de transmettre l’appel au service réel. L’application reçoit une réponse indiquant qu’un service réel a effectivement renvoyé, plutôt que celle qu’un développeur avait prédit qu’il renverrait.

Cette distinction semble minime. Son effet sur la précision est significatif.

Un développeur qui écrit une maquette pour une réponse d’API de paiement code sa compréhension du format de réponse de cette API au moment de la rédaction. Les lacunes dans cette compréhension – champs non documentés, gestion des cas extrêmes, détails de formatage subtils – deviennent des lacunes dans la précision de la simulation. Une réponse capturée ne présente pas de telles lacunes car elle provient de la véritable API. Il inclut tous les champs renvoyés par l’API, formatés exactement comme l’API l’a formaté, y compris les champs que le développeur ne savait pas rechercher et les cas extrêmes que l’API gère d’une manière que la documentation ne décrit pas entièrement.

Les outils qui implémentent la capture et la relecture du trafic relèvent un défi pratique qui rend la technique fiable : les champs non déterministes. Les réponses réelles de l’API contiennent des valeurs qui changent à chaque appel : horodatages, identifiants générés, jetons de session, identifiants de corrélation de requête. Si ces champs sont inclus textuellement dans le luminaire capturé, chaque test ultérieur échoue car ces valeurs ne correspondent plus à ce qui a été capturé.

Une femme assise devant un écran de test de bac à sable d’ordinateur.

Keploy résout ce problème en comparant plusieurs captures du même type d’interaction et en identifiant les champs qui diffèrent d’une capture à l’autre. Il exclut automatiquement ces champs des assertions de relecture, plutôt que de nécessiter une annotation manuelle. Ce qui reste est un appareil qui reflète avec précision les champs qui doivent être cohérents, sans bruit provenant de champs intrinsèquement variables. Lorsqu’un service en amont modifie son comportement après un déploiement, la réexécution de la session de capture produit des appareils mis à jour qui reflètent le nouveau comportement sans qu’un développeur ait besoin d’identifier ce qui a changé et de modifier manuellement les fichiers fictifs.

L’amélioration de la précision en termes concrets

Trois propriétés de précision spécifiques s’améliorent lorsque les tests sandbox utilisent le trafic capturé plutôt que des simulations écrites à la main.

  • Complétude de la réponse. Les réponses capturées contiennent tous les champs renvoyés par le service réel, pas seulement les champs que le développeur a pensé à inclure dans la simulation. Les applications qui lisent les champs des réponses de dépendance mais n’échouent pas visiblement lorsque ces champs sont manquants peuvent avoir des bogues latents qui apparaissent uniquement lorsqu’une réponse capturée confirme quels champs sont réellement présents par rapport à quels champs une simulation a été incorrectement incluse ou exclue.
  • Précision de la réponse aux erreurs. Les conditions d’erreur sont l’endroit le plus courant où les simulations s’écartent du comportement de dépendance réel. Les services réels renvoient des structures d’erreur spécifiques, avec des noms de champs spécifiques, des codes d’état HTTP spécifiques et des codes d’erreur spécifiques que le code d’application doit gérer correctement. Une simulation qui se rapproche du format d’erreur réussit les tests qui valident la gestion des erreurs. Une réponse d’erreur capturée teste l’application par rapport au format d’erreur exact produit par le service réel.
  • Monnaie comportementale. Un appareil sandbox dérivé du trafic capturé récemment reflète le comportement actuel du service réel. Une simulation écrite à la main reflète la manière dont le service réel se comportait lorsque la simulation a été écrite, il y a peut-être six mois. Si le service réel a déployé des modifications entre cette date et aujourd’hui, le luminaire capturé reflète ces modifications, contrairement à la maquette écrite à la main.

Les scénarios spécifiques où la capture et la relecture ont le plus d’impact

La capture et la relecture du trafic améliorent la précision du sandbox pour tout type d’intégration de dépendances, mais leur impact est plus prononcé dans des situations spécifiques.

  • Intégrations d’API tierces. Lorsque l’application s’intègre à des API que l’équipe ne contrôle pas (processeurs de paiement, transporteurs, fournisseurs d’identité, services d’IA), l’équipe n’a aucune visibilité sur le moment et la manière dont ces API changent. Les appareils capturés reflètent le comportement actuel de ces API et peuvent être actualisés en exécutant de nouvelles sessions de capture chaque fois que le service externe annonce une mise à jour.
  • Architectures de microservices avec déploiement indépendant. Lorsque chaque service se déploie selon son propre calendrier, les services en aval peuvent être testés par rapport à un comportement en amont qui est obsolète de plusieurs déploiements. Les sessions de capture planifiées après chaque déploiement en amont garantissent que les appareils de sandbox en aval reflètent le comportement actuel du service en amont, et non le comportement de la dernière fois que quelqu’un a mis à jour manuellement un fichier fictif.
  • Structures de réponse complexes. Une réponse JSON profondément imbriquée avec vingt champs, dont plusieurs sont des tableaux d’objets facultatifs, est véritablement difficile à répliquer avec précision à partir de la seule mémoire ou de la documentation. La maquette se termine par une version simplifiée : les champs que le développeur s’est souvenu d’inclure sont structurés de la même manière qu’il se souvenait de sa structure. Les réponses capturées ne présentent pas ce problème car elles proviennent du service réel. La complexité est déjà là.

L’écart restant

Trois hommes dans un décor à thème sportif observent un écran d'ordinateur. L’un est assis et tient une souris, tandis que les autres se tiennent à proximité avec intérêt.

La capture et la relecture du trafic réduisent l’écart de précision du bac à sable, mais ne le comblent pas complètement. Comprenez cela clairement avant de décider si la technique est suffisante pour un contexte de test donné.

Le bac à sable ne reflète toujours pas les données de production. Les réponses capturées proviennent d’environnements de préparation ou de développement, qui contiennent des données différentes de celles de production. Une application qui se comporte correctement par rapport aux réponses de préparation capturées peut se comporter différemment en production lorsque les données de réponse présentent des caractéristiques que les données de préparation n’ont pas.

Le bac à sable ne reflète toujours pas la charge de production. Les réponses capturées proviennent d’interactions uniques au cours d’une session d’enregistrement. Le comportement de production sous charge simultanée (conditions de concurrence, conflits de ressources, distribution de latence en cas de trafic de pointe) n’est pas capturé par l’enregistrement des interactions individuelles.

Ces lacunes restantes expliquent pourquoi les tests sandbox sont complétés par d’autres approches de test plutôt que remplacées par elles. La capture et la relecture du trafic ne complètent pas les tests du bac à sable. Il rend les tests du bac à sable aussi précis que possible dans le cadre de ses contraintes structurelles, de sorte que les échecs qu’il est conçu pour détecter sont réellement détectés plutôt que de passer inaperçus, car le bac à sable a été construit sur des hypothèses comportementales inexactes.

Lorsque les paramètres du bac à sable reflètent ce que les services réels renvoient plutôt que ce que les développeurs pensaient qu’ils le feraient, les tests du bac à sable détectent les échecs qu’ils sont censés détecter au lieu de la production. C’est l’amélioration de la précision apportée par la capture et la relecture du trafic – et pour la plupart des scénarios de tests d’intégration, elle est suffisamment importante pour modifier la vitesse à laquelle les tests sandbox remplissent leur objectif.

A lire également