Adaptateurs d'interface API logiciel / CLI – Tests Python

By | août 9, 2019

Expert Python

En écrivant un logiciel, nous sommes confrontés à de nombreuses interfaces.
L’interface publique de certains outils, modules, packages ou tout ce qui est généralement désigné sous le nom de API, le CLI, ou simplement l'interface utilisateur.
Dans ce post, lorsque je considère une interface, je fais spécifiquement référence aux API et CLI.

Parfois, nous trouvons un composant logiciel qui fait exactement ce que nous voulons, mais l’interface n’est pas ce que nous voulons.
C’est là que les adaptateurs d’interface logicielle viennent à la rescousse.
Les adaptateurs sont utiles à de nombreuses étapes de la conception et du développement de presque tout.

Les adaptateurs d’interface logicielle sont parfaits pour les tests fonctionnels.
Sur ce site, j'utilise un parfum de TDD qui se concentre sur les tests fonctionnels.
J'ai généralement deux objectifs:

  1. Je souhaite tester l'interface publique: API, CLI ou les deux.
  2. Je souhaite que les tests de ma suite de tests de régression soient aussi simples à écrire que possible, de sorte qu’il soit simple d’ajouter de nouveaux tests selon les besoins.

Souvent, ces objectifs sont contradictoires. L'API / CLI peut simplement ne pas être pratique pour des tests faciles.
C’est un endroit idéal pour développer un adaptateur d’interface.

Dans cet article, je vais décrire comment les adaptateurs d’interface peuvent être facilement spécifiés et implémentés en python.
En guise d’exemple, je vais décrire l’adaptateur d’interface nécessaire pour tester markdown.py.

Tests fonctionnels à l'interface publique

J'utilise souvent TDD lors de la conception et du développement de tout logiciel.
Je vais finir par écrire beaucoup de tests en cours de développement.
Cependant, les tests qui doivent vraiment, vraiment, être solides sont ceux qui testent l'interface et les fonctionnalités exposées publiquement.

Je veux une suite de tests qui vérifie entièrement l'interface publique et tous les comportements et fonctionnalités.
Par conséquent, je vais évidemment demander à ces tests d’utiliser l’interface externe / publique.

Concevoir pour le test

Lors de la conception et du développement, il peut s'avérer évident que l’interface publique est une tâche difficile à tester, soit parce qu’elle est lourde, soit parce qu’elle est lente.

Une solution consiste à ajouter à la spécification une API plus facile à utiliser (et / ou plus rapide).
Ceci est tout à fait valable et plutôt une bonne pratique.
Les utilisateurs de votre logiciel trouveront peut-être également l’interface étendue.

Cependant, vous devez toujours tester l'interface complète et vous convaincre par le biais de tests que la ou les interfaces ajoutées à des fins de test sont suffisantes.

Lorsque j'emprunte cette voie, j'ajoute toujours des tests qui utilisent l'interface peu pratique et comparent les résultats avec l'interface pratique.

Dans le cas de markdown.py, je suis toujours sur la clôture avec cela.
Je vais probablement étendre la spécification pour inclure une conception des fonctions de test.
Cependant, je souhaite que la suite de tests reste aveugle à ces ajouts.
Je peux le faire si je continue à utiliser le supplément DFT fonctions dans l'adaptateur.

CLI pour markdown.py

J'ai défini deux modèles d'interaction pour markdown.py:

  1. Passez un texte de démarque via stdin:
    chat unmile.mkd | python markdown.py> somefile.html
  2. Transmettez un nom de fichier en tant que paramètre:
    python markdown.py une_fichier.mkd> une_fichier.html

Maintenant, je ne viens pas de tirer ces modèles d’utilisation d’un chapeau.
C’est ainsi que j’ai utilisé markdown.pl et pandoc.

Donc, quand j’aurai fini, je devrais pouvoir remplacer python markdown.py avec perl markdown.pl dans ma suite de tests et obtenir les mêmes résultats.
Et pareil pour pandoc aussi.

C’est aussi la façon dont je vais habituellement utiliser markdown.py.

L'API que je veux pour tester facilement markdown.py

L'absence d'API python est assez ennuyeuse en ce qui concerne les tests.

Pour tester l’interface à partir d’une méthode de test python, je vais devoir utiliser quelque chose comme subprocess.Popen pour démarrer un autre processus python afin d’exécuter mon texte via markdown.py.

Ce n’est pas difficile, bien sûr. Cela rend simplement mon code de test moche si je l’ai partout.

Ce que je veux, c'est écrire un code comme celui-ci:

Mais je ne peux pas faire ça, car markdown.py n’a pas de run_markdown () méthode.

Je sais que je vais exécuter un certain nombre de chaînes différentes dans mon script markdown.py, en vérifiant que le résultat est correct.
Je veux rendre ce code aussi facile à écrire que possible.

Adaptateurs à la rescousse

Je sais que vous avez vu cela venir.
J'ai défini l'interface que j'ai et l'interface que je veux.

La prochaine étape logique consiste à implémenter un adaptateur d'interface pour relier les deux.

Adaptateur d'interface CLI / API logicielle pour markdown.py

Le code ci-dessous est l’adaptateur que je vais utiliser pour tester markdown.py.
Je respecte habituellement YAGNI pendant le développement.
Cependant, dans ce cas, je sais que je vais vraiment vouloir trois méthodes.

  1. une simple méthode run_markdown () qui effectue simplement la conversion.
  2. une méthode spécifique run_markdown_pipe () pour forcer l'interaction de canal stdin.
  3. une méthode spécifique run_markdown_file () pour forcer le nom de fichier comme interaction de paramètre.

markdown_adapter.py:

Utilisation de l'adaptateur d'interface run_markdown.py

Voici quelques exemples de code que j'ai mis en place pour que mon adaptateur fonctionne comme je le voulais.

Vous remarquerez probablement que j'ai déjà découvert que le test des chaînes qui passent par des tuyaux peut provoquer des différences de fin de ligne inattendues. C’est la raison pour laquelle il existe des appels de renvoi dans les comparaisons.

Cependant, étant donné que la syntaxe pour markdown et html traite les retours à la ligne et les sauts de ligne comme des espaces, je pense que je peux ignorer le contenu de fin de ligne.

Je peux me tromper, bien sûr. N'hésitez pas à me corriger.
En fait, s'il vous plaît, corrigez-moi s'il s'agit d'une hypothèse bozo.

try_run_markdown.py:

Cela ne fait toujours rien?

Oui. C'est vrai. Mon implémentation de ne fait toujours rien d’intéressant.
C’est toujours un bout.
Mais cela suffit pour commencer à écrire des tests, en particulier avec mon adaptateur implémenté.

Dans le cas où vous l'avez manqué …

Quelques autres articles directement pertinents sont listés ici:

Ensuite, quelques tests réels

La prochaine étape de ce projet consiste à lancer des tests réels.

Je vais commencer par doctest, puis passer à unittest, nez et pytest.
Aucune promesse quant à quelque chose d'utile qui sort de markdown.py