Découvrez comment intégrer facilement l'analyse statique, les tests unitaires et d'autres méthodes de test de logiciels C et C++ dans votre pipeline CI/CD. Inscrivez-vous pour la démo >>

Comment aborder les microservices de test

Par Nathan Jakubiak

5 juillet 2018

11  min lire

À bien des égards, le test d'une application de microservices n'est pas différent du test d'une application créée à l'aide d'une autre architecture. Le défi unique des microservices est le grand nombre de services qui composent une application, ainsi que le nombre de dépendances entre les services.

En tant qu'architecture pour la construction de systèmes complexes, les microservices gagnent en popularité au sein de la communauté du développement. Alors que les gens commencent à comprendre que ce n'est pas une panacée pour tous les problèmes d'architecture d'application, les applications qui partagent des défis liés aux dépendances et à la mise à l'échelle peuvent en tirer un grand bénéfice.

L'adoption des microservices est à la hausse, tout comme les difficultés associées à la compréhension tester les microservices. Toby Clemson de ThoughtWorks a fait un excellent travail de énumération des stratégies de test que vous voudrez peut-être utiliser dans une architecture de microservices (voir son article pour un bon aperçu des différents types de tests que vous voudrez peut-être créer), mais les connaissances générales sur la façon de créer et de maintenir ces différents types de tests en sont encore à leurs balbutiements .

Mais à bien des égards, le test d'une application de microservices n'est pas différent du test d'une application créée à l'aide d'une autre architecture. Les microservices utilisent des technologies bien connues, telles que REST ou les files d'attente, pour lesquelles l'industrie du logiciel dispose déjà d'outils de test et de bonnes pratiques bien établis. Le défi unique des microservices est le grand nombre de services qui composent une application, ainsi que les dépendances entre les services. En outre, chaque microservice doit toujours fonctionner correctement, même lorsque les autres microservices dont ils dépendent ne sont pas disponibles ou ne répondent pas correctement.

Les microservices suivent généralement deux modèles lorsqu'ils interagissent les uns avec les autres: l'orchestration et le réactif (chorégraphie). De nombreux microservices utilisent une approche «hybride» combinée. Dans cet article, je fournirai quelques stratégies pour résoudre certains des défis qui se posent lors de la création de tests automatisés pour les microservices qui utilisent ces différents modèles, en me concentrant sur les tests pour les microservices individuels (par opposition aux tests de bout en bout de l'ensemble de l'application. ).

Tester les microservices orchestrés

Un microservice utilisant l'orchestration effectuera un ou plusieurs appels explicites vers des services externes ou des dépendances. Les appels utilisent généralement un flux demande-réponse synchrone et accèdent souvent aux services REST. Si les services doivent être appelés dans un ordre spécifique, les appels à un service suivant ne sont pas effectués tant qu'une réponse n'est pas reçue pour un appel à un service antérieur. Étant donné qu'un service en appelle explicitement un autre, ils sont étroitement couplés.

Dans l'exemple ci-dessus, la création et l'exécution de tests pour le microservice Portfolio sont difficiles car le microservice Portfolio a des dépendances sur les microservices Accounts et Quotes, qui doivent être déployés dans l'environnement de test avec le microservice Portfolio. Le service Devis dépend d'un service tiers pour récupérer les cours des actions en temps réel, et les données renvoyées par ce service changent constamment.

Le fait de s'appuyer sur des services tiers ou des services développés par différentes équipes augmente considérablement la complexité de l'environnement de test. En outre, tout comportement inattendu du service Portfolio doit être testé, par exemple lorsque les services Comptes et / ou Devis ne sont pas disponibles, répondent lentement ou répondent avec des données inattendues. Il est important de pouvoir faire en sorte que ces services répondent avec différents types de comportement inattendu pour valider que le microservice Portfolio gère correctement les conditions d'erreur.

Comment simplifier les tests des architectures de microservices

La virtualisation des services à la rescousse !

Vous pouvez utiliser virtualisation des services pour simuler les réponses des microservices Comptes et devis. La virtualisation des services vous permet de définir des versions virtuelles des microservices Accounts and Quotes et de les déployer avec l'instance réelle du microservice Portfolio. La virtualisation des microservices est similaire à la virtualisation de tout autre type d'architecture de service ou d'application. Cela pourrait ressembler à ceci :

Une fois cette opération effectuée, le microservice Portfolio peut être testé indépendamment de ses deux dépendances.

Le défi suivant consiste à configurer différents environnements pour différents cas, par exemple lorsque les services Comptes et Devis présentent des comportements attendus et inattendus. Supposons que l'équipe souhaite tester le comportement du service Portfolio lorsque le service Comptes ou le service Devis répond lentement ou répond avec des conditions d'erreur. Cela peut nécessiter l'exécution d'au moins 5 ensembles de tests différents, chacun ayant une configuration d'environnement différente en tenant compte des temps de réponse lents, des réponses aux erreurs et du comportement normal et anormal des services dépendants.

Pour chaque exécution de test, l'environnement doit être mis dans la configuration correcte avant que les tests de cette configuration puissent s'exécuter. Dans cet exemple, nous nous retrouvons avec au moins cinq exécutions de test différentes, chacune ayant sa propre configuration pour l'environnement. Le module Environment Manager au sein de Parasoft Plateforme de test continu peut gérer ces différentes configurations d'environnement pour vous:

Ce processus n'est pas spécifique à une architecture de microservices - les mêmes types de problèmes se posent dans les architectures orientées services en général, ainsi que dans les applications monolithiques qui peuvent ne dépendre que d'une poignée de services. Dans une architecture de microservices, cependant, le nombre de services dépendants augmente considérablement. Dans un environnement de microservices avec des dizaines ou des centaines de services, la possibilité de créer, gérer et basculer par programme entre différentes configurations d'environnement pour différents scénarios de test est très importante et permet une réduction significative du temps et des efforts.

Gestion des modifications d'API dans les microservices orchestrés

Au fur et à mesure que les équipes font évoluer leurs microservices, il est inévitable que des modifications d'API soient apportées aux services. Un problème clé qui se pose avec les changements d'API est de savoir comment comprendre l'effet de ces changements sur les consommateurs des services.

Lorsqu'une équipe modifie l'API pour un microservice qu'elle est en train de créer, tous les tests qui valident ce microservice doivent être mis à jour en fonction des modifications apportées à l'API. Inversement, si des services virtuels sont utilisés pour simuler des microservices dépendants et une API pour l'un de ces changements de microservices dépendants, les services virtuels pour le microservice dépendant doivent être mis à jour pour refléter les modifications de l'API.

De nombreuses équipes utilisent OpenAPI, RAML ou une autre définition de service pour décrire les API de leurs microservices. Lorsque des définitions de service sont utilisées, le module Change Advisor Parasoft SOAtest et un Parasoft Virtualiser peut détecter automatiquement les API qui ont changé, puis refactoriser automatiquement les tests fonctionnels existants ou les services virtuels pour les mettre à jour avec tous les champs nouveaux et / ou supprimés de l'API. Les équipes peuvent créer des versions mises à jour de leurs définitions de service et utiliser l'assistant de modification pour comprendre l'impact des modifications sur leurs tests et services virtuels avant d'effectuer les modifications. Une fois les modifications apportées, Change Advisor permet de mettre à jour rapidement et facilement les actifs existants pour refléter les modifications au sein des microservices.

Test des microservices réactifs

L'un des principaux objectifs d'une architecture de microservices est de créer des composants indépendants. En conséquence, le déploiement, la mise à l'échelle et la mise à jour des services seront plus faciles. Cependant, cet objectif n'est pas complètement atteint lors de l'utilisation du modèle d'orchestration, car les microservices individuels ont des dépendances directes sur d'autres microservices. Une façon de résoudre ce problème consiste à utiliser le modèle de chorégraphie, également connu sous le nom de microservices «réactifs» ou «événementiels». Dans ce modèle, les microservices ne se référencent pas directement les uns les autres. Au lieu de cela, ils poussent les messages sur des flux d'événements auxquels d'autres microservices se sont abonnés.

Voir l'exemple suivant:

Dans cet exemple, disons que le service Portfolio a reçu pour instruction d'ajouter une position de stock. Plutôt que d'appeler directement le service Comptes, il publie un événement dans le flux d'événements «Position ajoutée». Le microservice Comptes s'est abonné à ce flux d'événements afin qu'il reçoive la notification. Il vérifie que l'utilisateur dispose de suffisamment de fonds sur son compte. Si tel est le cas, il réduit le montant des fonds dans le compte des utilisateurs et publie un événement dans le flux d'événements «Compte mis à jour». Si l'utilisateur ne dispose pas de suffisamment de fonds dans son compte, il peut publier un événement d'erreur dans un flux d'événements différent (non illustré pour la simplicité de l'exemple). Le microservice Portfolio est abonné au flux d'événements «Compte mis à jour», et lorsqu'il voit l'événement publié par le microservice Comptes, il met alors à jour son portefeuille en fonction de la confirmation du service Comptes.

La communication asynchrone dans ce type d'architecture présente l'avantage que les services sont fortement découplés les uns des autres - les instances de chaque service peuvent être remplacées, redéployées ou mises à l'échelle sans que les autres microservices s'en soucient. Le compromis est que la nature asynchrone des événements rend plus difficile de comprendre comment le système s'exécutera et quel sera le flux des événements. Selon l'ordre ou le type d'événements produits, le système peut se comporter de manière inattendue. Ceci est connu sous le nom de comportement émergent et constitue un défi inhérent au développement et au test de microservices chorégraphiés.

Modèle d'appels de commandes asynchrones

Il existe différents modèles de messagerie asynchrones qui relèvent de la catégorie plus large des microservices événementiels. Le modèle d'appels de commandes asynchrones est utilisé lorsque les microservices doivent être orchestrés à l'aide d'actions asynchrones - où un microservice doit appeler un autre microservice de manière asynchrone, tout en garantissant que le deuxième microservice a reçu le message. Dans ce modèle, les messages sont généralement échangés à l'aide de files d'attente.

Un cadre commun utilisé dans les architectures de microservices pour implémenter ce modèle est RabbitMQ. Une incarnation spécifique de ce modèle se produit lorsqu'un microservice a besoin de publier un événement pour un second microservice à traiter, puis d'attendre de lire un événement de «réponse» à partir de ce second microservice.

Prenons l'exemple de Portfolio dont nous venons de parler, dans lequel un appel d'API REST indique au microservice Portfolio d'ajouter une position. Le service Portfolio publie un événement dans la file d'attente Position ajoutée pour que le microservice Comptes le traite, puis attend que le service Comptes publie un événement de réponse dans la file d'attente Compte mis à jour afin que l'appel d'API REST puisse renvoyer les données reçues à partir de cet événement. Il existe deux manières différentes de configurer un scénario de test pour cet exemple:

  1. La première méthode consiste à créer un environnement avec les files d'attente nécessaires, dans lequel le service Portfolio est déployé mais pas le service Comptes. Étant donné que le service Comptes n'est pas déployé, le scénario de test devra simuler le comportement du service Comptes en publiant l'événement attendu à partir du service Comptes au moment approprié. Un scénario de test Parasoft SOAtest sera construit avec deux tests: un qui exécute l'API REST du service Portfolio et un second test qui publie l'événement à partir du service Accounts. Les tests doivent être configurés pour s'exécuter simultanément afin que l'événement du service Comptes soit publié pendant que le service Portfolio écoute l'événement.
  2. Au lieu de simuler le service Comptes à l'aide d'un test pour publier son événement, il peut être utile de créer un service virtuel réutilisable qui écoute les événements publiés dans la file d'attente de position ajoutée et publie un événement résultant dans la file d'attente de mise à jour du compte. Ce microservice virtuel serait alors réutilisable dans plusieurs scénarios de test différents qui pourraient en avoir besoin.

La première approche est simple et constitue un actif de test autonome qui n'a pas de dépendances externes supplémentaires sur l'infrastructure de test. La seconde approche est réutilisable et est une simulation plus proche du comportement réel du système. La deuxième approche, cependant, a le coût de la création, du déploiement et de la gestion d'un actif virtuel distinct.

Une variante du modèle d'appels de commandes asynchrones est un microservice qui écoute dans une file d'attente un événement entrant, traite l'événement, puis publie un événement de suivi sur une file d'attente différente pour un ou plusieurs autres microservices à traiter:

Dans cet exemple, le microservice Invoice est le service qui doit être testé. Le service Payments publie un événement dans la file d'attente RabbitMQ Payment Processed pour que le service Invoice le récupère. Le microservice Invoice lit l'événement dans la file d'attente, crée une facture, puis publie un événement dans la file d'attente Invoice Created pour demander au microservice Email d'envoyer un e-mail au client avec la facture. Pour créer un scénario de test pour le microservice Invoice, un environnement de test peut être configuré qui contient deux files d'attente RabbitMQ et le microservice Invoice déployé. Un scénario de test Parasoft SOAtest peut être construit pour publier un événement de traitement de paiement dans la file d'attente Paiement traité. Le scénario s'abonne ensuite à la file d'attente de création de facture pour valider que l'événement de création de facture approprié est publié en réponse par le service de facturation. Il s'agit d'un scénario de test très simple qui teste bien le service Invoice de manière isolée.

Modèle d'événement Firehose

Le modèle d'événement Firehose est utilisé lorsque différentes sources produisent un très grand nombre d'événements qui doivent être livrés rapidement à différents consommateurs via un concentrateur commun. Dans ce modèle, les messages sont échangés via des rubriques (contrairement au modèle d'appels de commandes asynchrones où les messages sont échangés via des files d'attente). Un cadre commun utilisé pour implémenter le modèle d'événement Firehose est le Apache Kafka framework, et cela ressemble un peu à ceci:

Disons que nous voulons tester un seul microservice qui s'abonne à un sujet Kafka, traite les événements qu'il reçoit, puis publie ses résultats dans un deuxième sujet Kafka. Par exemple, quelque chose comme ceci:

Dans cet exemple, nous avons un microservice de prévision qui s'abonne à un sujet de données météorologiques qui collecte de nombreuses données météorologiques différentes provenant de nombreuses sources différentes. Il traite ensuite ces données pour mettre à jour son modèle de prévision et publie les données de prévision dans la rubrique Données de prévision. Dans ce cas, nous devons valider que le service de prévision publie les événements attendus dans la rubrique Données de prévision pour un ensemble spécifique d'événements de données météorologiques.

Cela serait fait en configurant un environnement de test contenant les deux sujets Kafka et le service de prévision déployé. Le scénario de test publie d'abord les événements nécessaires dans la rubrique Données météorologiques, puis s'abonne à la rubrique Données de prévision pour vérifier que les événements de données de prévision corrects ont été publiés par le service de prévision. Plusieurs scénarios de test différents devraient être construits pour vérifier les différents types et ordre des événements susceptibles d'être traités par le microservice de prévision.

Il s'agit d'un scénario de test relativement simple. Le fait que le microservice Forecast soit découplé des autres microservices a l'heureux effet secondaire que le test du service Forecast est également découplé des microservices. Dans ce cas, vous n'avez pas besoin de configurer un environnement complexe avec des services virtuels - vous pouvez simplement créer des scénarios de test qui publient des événements et vérifier que les événements corrects sont créés en réponse.

Configuration des environnements de test

De nombreuses équipes de microservices ont adopté un processus d'intégration continue / déploiement continu (CI / CD) pour créer, tester et déployer des microservices conteneurisés afin d'automatiser le processus et de réduire les risques associés au déploiement des mises à jour.

Dans ce processus, une image de conteneur contenant le microservice est automatiquement créée et déployée dans un environnement de test (souvent géré par Kubernetes ou une distribution basée sur Kubernetes comme OpenShift), où le microservice peut être validé avant d'être poussé dans des tests de bout en bout et enfin en production. Je recommanderais de lire CI / CD pour microservices conteneurisés et un Conception de microservices: intégration continue. Ces deux articles décrivent bien ce type de processus.

Virtualisation des services pour tester les microservices

Certains des modèles de test dont nous avons discuté reposent sur l'utilisation de services virtuels pour les microservices dépendants. Ces services virtuels doivent être fortement composables et facilement déployables pour les mêmes raisons que les microservices qu'ils simulent sont composables. Pour que la virtualisation des services fonctionne dans ces environnements, vous devez créer des services virtuels conteneurisés qui peuvent être facilement déployés.

Pour créer un service virtuel conteneurisé, vous pouvez prendre une image de base qui contient Parasoft Virtualize et toutes ses dépendances, et la superposer avec une autre image contenant toute la configuration des actifs virtuels pour le service virtuel. La nouvelle image du service virtuel peut être déployée en tant que conteneur dans l'environnement Docker / Kubernetes avec le conteneur du microservice testé et toutes ses dépendances (virtualisées).

Conclusion

À mesure que les équipes adoptent les microservices, il est important de comprendre comment les tester suffisamment. Les modèles de messagerie et les modèles de test associés dont j'ai parlé ici ne sont pas nouveaux, mais le besoin d'utiliser ces modèles s'est considérablement accru à mesure que les microservices deviennent plus courants et que de plus en plus d'applications adoptent un paradigme de microservices.

À créer et déployer des scénarios de test pour vos microservices avec une flexibilité maximale, vous pouvez tirer parti Parasoft SOAtest, Parasoft Virtualiser, et le Plateforme de test continu Parasoft pour garantir la plus haute qualité et fiabilité de vos microservices.

Comment simplifier les tests des architectures de microservices

Par Nathan Jakubiak

Nathan est directeur du développement chez Parasoft. Lui et ses équipes développent des capacités produit dans les domaines des tests d'interface utilisateur (Selenic), des tests d'API (SOAtest), de la virtualisation des services (Virtualize) et des tests unitaires (Jtest). Il travaille chez Parasoft depuis 2000.

Recevez les dernières nouvelles et ressources sur les tests de logiciels dans votre boîte de réception.