Assurance qualité manuelleIngénieur QA Manuel

Lors de la validation d'une migration de schéma **GraphQL** à partir d'une ancienne API **REST** qui sert des clients mobiles hétérogènes avec des cycles de vie de support de version variables, quelle stratégie de test manuel systématique déploieriez-vous pour garantir la compatibilité descendante tout en vérifiant que l'utilisation des champs obsolètes déclenche les mécanismes de dégradation appropriés ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse à la question

Établissez une méthodologie de matrice de version systématique en documentant d'abord quels champs spécifiques chaque version du client mobile consomme à l'aide de Charles Proxy ou Burp Suite pour intercepter le trafic de production, créant une carte de dépendance qui coréla avec les versions d'applications iOS et Android aux champs du schéma GraphQL. Exécutez des tests exploratoires validés par contrat en élaborant des requêtes manuelles qui imitent les requêtes des clients hérités, en injectant délibérément des valeurs nulles dans les champs obsolètes pour vérifier que les clients mobiles gèrent les données manquantes par des bornes d'erreur plutôt que de planter. Mettez en œuvre des tests de shadow en exécutant des requêtes REST et GraphQL parallèles via des collections Postman, en comparant les charges utiles de réponse pour une équivalence sémantique tout en surveillant que les en-têtes de dépréciation et les directives @deprecated déclenchent un journalisation côté client sans casser l'interface utilisateur.

Situation de la vie

Description du problème

Notre plateforme de commerce électronique migrait son catalogue de produits d'API REST vers un schéma GraphQL unifié pour soutenir un nouveau moteur de recommandation, mais nous supportions des versions iOS datant de v12.4 (sortie en 2019) et des versions Android jusqu'au niveau d'API 28 (Android 9), créant une matrice de plus de 15 versions d'applications actives avec des capacités client GraphQL variables. Le risque critique était que les clients iOS v14.2 s'appuyaient sur un champ obsolète productVariants qui était remplacé par productOptions, et si ce champ renvoyait des valeurs nulles inattendues au lieu de tableaux vides pendant la période de dépréciation, la logique de parsing Swift ferait planter l'application. De plus, les clients Android utilisant le Apollo Client v2.5 géraient la nullabilité différemment des implémentations Alamofire iOS, ce qui signifie que le même changement de schéma pouvait entraîner une corruption silencieuse des données sur une plate-forme tout en provoquant un plantage sur une autre.

Solution 1 : Tests de régression de bout en bout complets

Nous avons envisagé d'exécuter des suites de régression complètes sur des appareils physiques pour chaque version d'OS supportée, en naviguant manuellement à travers les flux du catalogue de produits pour vérifier la cohérence visuelle et l'intégrité des données sur toutes les plates-formes. Cette approche fournirait une confiance absolue que les fonctionnalités côté utilisateur fonctionnaient correctement et détecteraient des problèmes d'interface utilisateur spécifiques à chaque plateforme liés à la liaison de données GraphQL. Cependant, cela nécessitait l'accès à plus de 40 appareils physiques et environ trois semaines de temps de test, ce qui dépassait notre délai de migration de deux semaines et ne garantissait pas la détection de violations subtiles des contrats API qui n'apparaissaient que dans des conditions réseau spécifiques.

Solution 2 : Tests de contrat API avec des réponses de client fictives

La deuxième approche consistait à utiliser Postman et Mockoon pour simuler les structures de requête exactes envoyées par les clients mobiles hérités, validant que le schéma GraphQL retournait des réponses JSON syntaxiquement correctes correspondant aux structures de charge utile REST historiques. Cette méthode était considérablement plus rapide, nous permettant de tester toutes les combinaisons de versions en trois jours, et fournissait une validation précise des en-têtes de dépréciation et de la nullabilité des champs. Malheureusement, ce test purement synthétique manquait des comportements de parsing critiques spécifiques à la plate-forme, tels que l'échec du protocole Swift Codable iOS sur des clés nulles inattendues versus manquantes, qui ne se manifestaient que dans des environnements clients réels.

Solution 3 : Tests d'interception basés sur les risques avec des analyses de production

Nous avons finalement choisi une stratégie hybride qui analysait les données d'Firebase Analytics pour identifier les trois principales versions d'OS par plateforme représentant 85 % de notre base d'utilisateurs active, puis utilisé Charles Proxy pour intercepter le trafic en direct et réécrire les réponses REST en requêtes GraphQL tout en surveillant la stabilité des clients. Cela nous a permis de tester des modèles de requêtes du monde réel et des conditions de latence réseau tout en concentrant les efforts de validation manuels sur des combinaisons de versions à fort impact, complétées par des tests de contrat automatisés pour les cas limites. Nous avons choisi cela car cela équilibré la couverture des risques avec les contraintes de temps, donnant confiance que la migration n'affecterait pas la majorité des utilisateurs tout en identifiant des problèmes de compatibilité spécifiques comme le bug de gestion des null iOS.

Solution choisie et résultat

Nous avons mis en œuvre la Solution 3, en concentrant nos tests manuels sur iOS 14.2, 15.0 et 16.0 ainsi que sur Android 10, 11 et 12, utilisant Charles Proxy pour simuler la dépréciation du champ productVariants en renvoyant des valeurs nulles et en surveillant les plantages. Lors des tests de iOS v14.2, nous avons découvert que lorsque le champ obsolète retournait null, l'application cliente plantait avec une erreur EXC_BAD_ACCESS au lieu d'afficher l'UI de secours, révélant que la borne d'erreur Swift analysait incorrectement la réponse d'erreur GraphQL. Nous avons documenté cela comme un défaut critique, mis en œuvre un changement de schéma côté serveur pour renvoyer des tableaux vides avec des avertissements de dépréciation au lieu de valeurs nulles pour une période de six mois, et établi des alertes de surveillance pour les taux d'erreurs GraphQL segmentés par version d'application ; la migration s'est déroulée sans aucun crash sur les versions supportées.

Ce que les candidats oublient souvent

Comment vérifiez-vous que les limites de profondeur de requête GraphQL et le scoring de complexité sont correctement appliqués lors des tests manuels sans accès aux journaux côté serveur ou outils de tests de charge automatisés ?

Beaucoup de candidats supposent que le test de sécurité GraphQL nécessite des scripts automatisés, mais les testeurs manuels peuvent construire des requêtes imbriquées à l'aide de GraphiQL ou Insomnia en créant intentionnellement des références circulaires ou des objets profondément imbriqués pour déclencher des mécanismes de protection contre le DoS. Vous devez vérifier que l'API renvoie des codes d'erreur spécifiques comme GRAPHQL_VALIDATION_FAILED ou QUERY_TOO_COMPLEX plutôt que des erreurs génériques 500, et tester que les calculs de complexité tiennent correctement compte des multiplicateurs de champ lorsque des alias sont utilisés pour demander le même champ plusieurs fois sous différents noms dans une seule requête. Cette vérification manuelle garantit que l'analyse de complexité du serveur compte précisément les champs demandés et rejette les requêtes qui dépassent les seuils configurés avant qu'elles ne consomment des ressources de base de données.

De plus, les candidats oublient souvent de tester que les requêtes persistantes (liste blanche des requêtes autorisées) rejettent les requêtes manuelles arbitraires dans les environnements de production, ce qui est critique pour empêcher des attaques d'épuisement des ressources. Vous pouvez vérifier cela en essayant d'exécuter des requêtes ad hoc via Postman qui dévient de l'empreinte de requête persistante, en veillant à ce que le serveur renvoie une erreur PersistedQueryNotFound ou équivalente plutôt que d'exécuter la requête. Cette frontière de sécurité empêche les attaquants de créer des requêtes gourmandes en ressources qui pourraient dégrader les performances du système pour les utilisateurs légitimes.

Quelle est l'approche systématique pour tester le schéma GraphQL stitching ou la fédération lorsque plusieurs microservices contribuent des champs au même type d'entité, en particulier concernant la propagation des erreurs lorsqu'un service est dégradé ?

Dans les architectures Apollo Federation ou de stitching de schéma, les débutants testent souvent chaque service de manière isolée et manquent de tester les échecs partiels où le type User pourrait combiner des champs du Service d'Authentification (critique) et du Service de Préférences (non critique). Vous devez déclencher manuellement des échecs dans les services en aval en utilisant des techniques Chaos Monkey ou en bloquant des points de terminaison spécifiques avec Charles Proxy, puis vérifier que le Gateway renvoie des données partielles avec des champs nuls et des chemins d'erreur spécifiques dans le tableau errors, plutôt que de faire échouer l'ensemble de la requête et de provoquer un échec complet de la page. Cette approche valide la résilience de la couche de fédération et garantit que les parcours utilisateurs critiques restent fonctionnels même lorsque des services non essentiels rencontrent des pannes.

L'insight clé consiste à valider que les directives @defer et @stream gèrent correctement les champs à résolution lente sans bloquer l'ensemble de l'UI, et que le client reçoit des métadonnées d'erreur exploitables pour afficher le contenu de secours pour des composants spécifiques tout en rendant les données disponibles des services sains. Les testeurs doivent vérifier que la partie extensions de la réponse GraphQL contient des informations de traçage de service précises indiquant quel microservice spécifique a échoué, permettant au frontend de prendre des décisions intelligentes sur le contenu à cacher ou à afficher dans un état dégradé. Les tests appropriés de propagation des erreurs garantissent que les utilisateurs peuvent toujours compléter des transactions essentielles même lorsque des fonctionnalités complémentaires comme les recommandations ou les analyses sont temporairement indisponibles.

Comment distinguez-vous entre la nullabilité prévue GraphQL (champs qui peuvent légitimement être nuls) et les défauts réels lors des tests d'applications utilisant des outils de génération de code comme Apollo Codegen ou GraphQL Codegen ?

Les candidats ont souvent du mal avec les types TypeScript ou Swift générés qui marquent les champs comme optionnels (nullables) lorsque la logique métier exige effectivement qu'ils soient présents, ce qui conduit à de la confusion sur le fait qu'une valeur nulle représente un bug ou un état vide valide. Vous devez examiner les points d'exclamation (!) du schéma par rapport aux types clients générés, tester les conditions limites en manipulant manuellement les réponses JSON dans Charles Proxy pour injecter des valeurs nulles dans des champs de schéma non nullables pour vérifier que le serveur valide correctement les données avant d'envoyer des réponses au client. Cette distinction est cruciale car une valeur nulle dans un champ de schéma non nullable indique un défaut côté serveur, tandis qu'une valeur nulle dans un champ nullable peut représenter une absence légitime de données.

De plus, vous devez vérifier que l'application cliente gère correctement la nullabilité fondée sur le schéma en vérifiant que la compilation en mode strict de TypeScript réussit lors de l'accès à des champs potentiellement nuls, garantissant que les types générés protègent réellement contre les exceptions de pointeur nul à l'exécution plutôt que de simplement correspondre au schéma superficiellement. Cela nécessite de comprendre que les champs non nullables GraphQL ne devraient jamais renvoyer null du serveur, tandis que les champs nullables devraient toujours être gérés avec une chaîne optionnelle ou des vérifications nulles dans le code client, quelles que soient les hypothèses de logique métier concernant la présence constante des données. Les développeurs oublient souvent d'ajouter ces vérifications défensives lorsque la logique métier suggère que les données devraient toujours exister, donc un test manuel rigoureux de l'injection de null aide à attraper des plantages potentiels avant qu'ils n'atteignent des utilisateurs en production.