Test de bout en bout des microservices avec Catcher

Bon après-midi Je voudrais introduire un nouvel outil de test de bout en bout des microservices - Catcher
logo


Pourquoi tester?


Pourquoi ai-je besoin de tests e2e? Martin Fowler recommande de l' éviter au profit de tests plus simples.


Cependant, plus les tests sont élevés, moins il y a de réécriture. Les tests unitaires sont presque entièrement réécrits. Les tests fonctionnels doivent également passer votre temps en cas de refactoring sérieux. Les tests de bout en bout devraient tester la logique métier, et cela change moins souvent.


De plus, même une couverture de test complète de tous les microservices ne garantit pas leur interaction correcte. Les développeurs peuvent implémenter le protocole de manière incorrecte (erreurs dans le nom / type de données).


Ou implémentez de nouvelles fonctionnalités en vous appuyant sur le schéma de données de la documentation et obtenez une surprise sur l'environnement du produit sous la forme d'erreurs de non-concordance de schéma: un gâchis dans les données ou quelqu'un a oublié de mettre à jour le schéma de données.


Et les tests de chacun des services concernés seront verts.


Pourquoi des tests automatiques?


Vraiment. Sur mon ancien lieu de travail, il a été décidé que passer du temps à déployer des tests automatisés était trop long, difficile et coûteux. Le système n'est pas volumineux (10 à 15 microservices avec un kafka commun). Le CTO a décidé que "les tests ne sont pas importants, l'essentiel est que le système fonctionne." Testé manuellement sur plusieurs environnements.


À quoi cela ressemblait (processus général):


  1. Convenez avec d'autres développeurs (déploiement de tous les microservices participant à la nouvelle fonctionnalité)
  2. Déployer tous les services
  3. Se connecter à Kafka à distance (double SSH en DMZ)
  4. Connectez-vous aux journaux k8s
  5. Formez et envoyez un message à Kafka manuellement (Dieu merci, Json)
  6. Regardez les journaux, essayez de comprendre si cela a fonctionné ou non.

Et maintenant, il y a un peu de goudron dans ce fût de chocolat: la plupart des tests devaient être créés par les utilisateurs, car la réutilisation des tests existants est difficile.


Premièrement, du fait que le système est distribué, plusieurs services avaient leurs propres bases de données contenant des informations sur les utilisateurs.


Deuxièmement, le kafka a été utilisé pour le stockage permanent des données. C'est-à-dire même si les informations sont supprimées / modifiées dans la base de données, le service les relira quand même au redémarrage.


À quoi ressemblait l'enregistrement d'un nouvel utilisateur de test (approximativement):


  1. Entrez toutes les données (nom, courrier, etc.)
  2. Saisie de données personnelles (adresse, téléphone, toutes informations fiscales)
  3. Saisie des données bancaires (en fait, des données bancaires)
  4. Répondez à 20 à 40 questions (ressentez-vous déjà de la douleur?)
  5. Passez par l' identification IDNow (merci, ils l'ont désactivé sur l'environnement de développement, merci, sur scène c'est environ 5 minutes ou plus, car leur sandbox est parfois surchargé)
  6. À cette étape, l'ouverture d'un compte dans un système tiers est requise et rien ne peut être fait via le front-end. Vous devez vous rendre par ssh à kafka et travailler comme un faux serveur (envoyer un message que le compte est ouvert)
  7. Ensuite, vous devez accéder à un autre front-end dans le compte personnel du modérateur et confirmer l'utilisateur.

Super, l'utilisateur est enregistré! Maintenant, une petite mouche dans la pommade: certains tests nécessitent plus d'un utilisateur de test. Et parfois, les tests échouent la première fois.


Et comment est la vérification des nouvelles fonctionnalités et la confirmation de l'équipe commerciale?
Il faut tout de même répéter sur l'environnement suivant.


Inutile de dire qu'après un certain temps, vous commencez à vous sentir comme un singe, qui ne fait que ce qu'il appuie, enregistrant les utilisateurs.


Certains autres développeurs (généralement le frontal) ont eu des problèmes de connexion à kafka. Et avec un bug dans le terminal avec une chaîne de 80+ caractères (tout le monde ne connaissait pas tmux).


Avantages :


  • pas besoin de configurer / écrire quoi que ce soit. Testez directement sur un environnement en cours d'exécution.
  • ne nécessite pas de qualifications élevées (des spécialistes moins chers peuvent le faire)

Inconvénients :


  • prend beaucoup de temps (le plus loin, le plus)
  • généralement, seules les nouvelles fonctionnalités sont testées (il n'est pas clair si la fonctionnalité existante est défectueuse)
  • Souvent, des développeurs qualifiés sont engagés dans des tests manuels (des spécialistes coûteux font un travail bon marché).

Comment automatiser?


Si vous lisez ceci en hochant la tête et en disant: "Oui, c'est un excellent processus, les gars savent ce qu'ils font", alors cela ne vous intéressera pas.


Les tests e2e faits maison sont de deux types et dépendent de celui des programmeurs qui était le plus libre:


  • le backend qui vit dans votre environnement de test. Il protège la logique de test, qui se déplace à travers les points de terminaison. Il peut même être partiellement automatisé en raison de l'interaction avec CI.
  • Un script avec la même logique filaire. La seule différence est que vous devez aller quelque part et l'exécuter à partir de là. Si vous faites confiance à votre CI, vous pouvez même l'exécuter automatiquement.

Ça sonne bien. Des problèmes?


Oui, ces tests sont écrits sur ce que la personne qui les écrit sait. Généralement, ce sont des langages de script comme rub ou python, qui vous permettent d'écrire rapidement et facilement ce genre de chose. Cependant, parfois, vous pouvez tomber sur un tas de scripts bash, C ou quelque chose de plus exotique (j'ai passé une semaine à copier mon vélo sur des scripts bash en python parce que les scripts n'étaient plus extensibles et personne ne savait vraiment comment ils fonctionnaient et ce qu'ils testaient) .
Exemple de projet ici


Avantages :


  • automatisation

Inconvénients :


  • des exigences supplémentaires pour les qualifications des développeurs sont possibles (s'ils développent en Java et que les tests ont été écrits en Python)
  • écrire du code pour tester le code écrit (qui testera les tests?)

Y a-t-il quelque chose de prêt?


Bien sûr, regardez dans la direction de BDD . Il y a un concombre , il y a une jauge .


En bref, le développeur décrit le scénario métier dans un langage spécial, puis implémente les étapes du script dans le code. Le langage est généralement lisible par l'homme et il est supposé qu'il sera lu / écrit non seulement par les développeurs, mais aussi par les chefs de projet.


Les scripts ainsi que la mise en œuvre des étapes sont également dans un projet distinct et exécutés par des produits tiers (Cucumber / Gauge / ...).


Le script ressemble à ceci:


Customer sign-up ================ * Go to sign up page Customer sign-up ---------------- tags: sign-up, customer * Sign up a new customer with name "John" email "jdoe@test.de" and "password" * Check if the sign up was successful 

Et mise en œuvre:


 @Step("Sign up as <customer> with email <test@example.com> and <password>") public void signUp(String customer, String email, String password) { WebDriver webDriver = Driver.webDriver; WebElement form = webDriver.findElement(By.id("new_user")); form.findElement(By.name("user[username]")).sendKeys(customer); form.findElement(By.name("user[email]")).sendKeys(email); form.findElement(By.name("user[password]")).sendKeys(password); form.findElement(By.name("user[password_confirmation]")).sendKeys(password); form.findElement(By.name("commit")).click(); } @Step("Check if the sign up was successful") public void checkSignUpSuccessful() { WebDriver webDriver = Driver.webDriver; WebElement message = webDriver.findElements(By.className("message")); assertThat(message.getText(), is("You have been signed up successfully!")); } 

Projet complet ici


Avantages :


  • la logique métier est décrite dans un langage lisible par l'homme et stockée en un seul endroit (peut être utilisée comme documentation)
  • des solutions prêtes à l'emploi sont utilisées, les développeurs ont seulement besoin de savoir comment les utiliser

Inconvénients :


  • les gestionnaires ne liront pas et n'écriront pas de scripts
  • vous devez suivre à la fois les spécifications et leur mise en œuvre (et cela consiste à écrire du code et à modifier les spécifications)

Alors pourquoi Catcher?


Bien sûr, pour simplifier le processus.


Le développeur écrit uniquement des scripts dans json / yaml et Catcher les exécute. Le script se compose d'étapes exécutées séquentiellement, par exemple:


 steps: - http: post: url: '127.0.0.1/save_data' body: {key: '1', data: 'foo'} - postgres: request: conf: 'dbname=test user=test host=localhost password=test' query: 'select * from test where id=1' 

Catcher prend en charge les modèles jinja2, vous pouvez donc utiliser des variables au lieu des valeurs câblées dans l'exemple ci-dessus. Les variables globales peuvent être stockées dans des fichiers d'inventaire (comme dans un ensemble), extraites de l'environnement et enregistrées de nouvelles:


 variables: bonus: 5000 initial_value: 1000 steps: - http: post: url: '{{ user_service }}/sign_up' body: {username: 'test_user_{{ RANDOM_INT }}', data: 'stub'} register: {user_id: '{{ OUTPUT.uuid }}' - kafka: consume: server: '{{ kafka }}' topic: '{{ new_users_topic }}' where: equals: {the: '{{ MESSAGE.uuid }}', is: '{{ user_id }}'} register: {balance: '{{ OUTPUT.initial_balance }}'} 

De plus, vous pouvez exécuter des étapes de test:


 - check: # check user's initial balance equals: {the: '{{ balance }}', is: '{{ initial_value + bonus }}'} 

Vous pouvez également exécuter certains scripts à partir d'autres scripts, ce qui a un excellent effet sur la propreté et la réutilisation du code (y compris le lancement d'une partie seulement des étapes via le système de balises, le lancement différé, etc.).


 include: file: register_user.yaml as: sign_up steps: # .... some steps - run: include: sign_up # .... some steps 

L'insertion et l'utilisation de scripts peuvent résoudre le problème de l'attente d'une ressource (attendre un service pendant son démarrage).


En plus des étapes prédéfinies intégrées et d'un référentiel supplémentaire), il est possible d'écrire vos modules en python (juste hérité de ExternalStep ) ou dans tout autre langage:


 #!/bin/bash one=$(echo ${1} | jq -r '.add.the') two=$(echo ${1} | jq -r '.add.to') echo $((${one} + ${two})) 

et utiliser:


 --- variables: one: 1 two: 2 steps: - math: add: {the: '{{ one }}', to: '{{ two }}'} register: {sum: '{{ OUTPUT }}'} 

Les scripts sont placés dans le fichier Docker et exécutés via CI.


Cette image peut également être utilisée dans Marathon / K8 pour tester l'environnement existant. En ce moment, je travaille sur un backend (similaire à AnsibleTower) pour rendre le processus de test encore plus facile et plus pratique.


Avantages :


  • pas besoin d'écrire du code (uniquement dans le cas de modules personnalisés)
  • changer d'environnements via des fichiers d'inventaire (comme dans l'ensemble)
  • Vous pouvez utiliser vos propres modules (dans n'importe quelle langue, même sh)

Inconvénients :


  • syntaxe non lisible par l'homme (par rapport aux outils BDD)

Au lieu d'une conclusion


Quand j'ai écrit cet outil, je voulais juste réduire le temps que je passe habituellement sur les tests. Il se trouve que chaque nouvelle entreprise doit écrire (ou réécrire) un tel système.


Cependant, l'outil s'est avéré plus flexible que ce à quoi je m'attendais. Si quelqu'un s'intéresse à l'article (ou à l'outil lui-même), je peux vous dire comment utiliser Catcher pour organiser des migrations centralisées et mettre à jour le système de microservices.


Mise à jour


Comme je l'ai indiqué dans les commentaires, le sujet n'est pas divulgué.
J'essaierai d'indiquer ici les thèses les plus controversées.


  • les tests de bout en bout ne sont pas des tests unitaires. J'ai déjà fait référence à M. Fowler dans cet article. Les tests unitaires sont dans le projet de backend de test (répertoire de tests standard) et exécutés à chaque fois que le code change en CI. Et les tests e2e sont un projet distinct, ils prennent généralement plus de temps, testent l'interaction de tous les services participants et ne savent rien du code de votre projet (boîte noire).
  • vous ne devez pas utiliser Catcher pour les tests d'intégration (et ci-dessous). C'est cher. Il est beaucoup plus rapide d'écrire un test sur votre PJ pour le backend actuel. Vous n'avez besoin de tests de bout en bout que si votre logique métier est répartie sur 2 services ou plus.
  • Catcher est également un BDD. De mon point de vue, le principal avantage par rapport à Jauge / Concombre est les modules prêts à l'emploi et la facilité de les ajouter. Idéalement, seul un test est écrit. Dans la dernière entreprise, j'ai écrit les 4 tests sur des composants standard, sans rien programmer. En conséquence, les exigences de qualification (et le prix d'un tel spécialiste) seront plus faibles. Seule la connaissance de json / yaml et la capacité de lire les spécifications sont nécessaires.
  • Pour écrire des tests Catcher, vous devrez apprendre Catcher-DSL. Hélas, c'est vrai. Au début, je voulais faire écrire les tests eux-mêmes, directement depuis le microphone. Mais alors j'ai pensé qu'ils me tireraient alors comme inutile;) Comme mentionné ci-dessus - Catcher DSL est le json / yaml standard et les spécifications d'étape. Rien de fondamentalement nouveau.
  • Vous pouvez utiliser des technologies standard et écrire quelque chose de votre choix. Cependant, nous parlons de microservices. Il s'agit d'un grand nombre de technologies et d'armes nucléaires différentes et d'un grand nombre d'équipes. Et si pour la commande java junit + testcontainers est le choix évident, l'équipe erlang choisira autre chose. Dans une grande entreprise avec plus de 30 équipes au sommet, ils décideront que tous les tests doivent être soumis à la nouvelle équipe infrastructure / qa. Pouvez-vous imaginer à quel point ils sont heureux dans ce zoo?
  • Si vous avez 4 à 5 tests e2e, vous pouvez tout écrire dans n'importe quel langage de script et l'oublier. Cependant, si la logique change avec le temps, après 2 à 4 ans, vous devrez refactoriser, distribuer directement la logique métier des tests et la mise en œuvre des méthodes d'accès aux composants testés. Donc, à la fin, vous écrivez votre Catcher, mais pas si flexible. Il m'a fallu 4 implémentations pour comprendre cela;)

Source: https://habr.com/ru/post/fr435452/


All Articles