Vaut-il vraiment la peine de tester un client API?

38

C'est quelque chose qui me trouble depuis un moment. Vaut-il vraiment la peine de tester un client API?

Supposons que vous créez une petite classe pour extraire les appels à une API REST de petshop. Le petshop est une API très simple, et il a un ensemble de méthodes de base:

  • listProducts()
  • getProductDetails(ProductID)
  • addProduct(...)
  • removeProduct(ProductID)

Pour tester cela, nous devions soit créer un service factice, soit simuler les réponses. Mais cela semble exagéré; Je comprends que nous voulons nous assurer que nos méthodes ne cessent pas de fonctionner avec des erreurs typo / syntax, mais comme nous écrivons des fonctions qui appellent des méthodes distantes et que nous créons ensuite de fausses réponses à partir de ces méthodes distantes, il semble que un gaspillage d'effort et que nous testons quelque chose qui ne peut pas vraiment échouer. Pire encore, si la méthode distante change, nos tests unitaires échoueront en cas d'échec de la production.

Je suis presque sûr que je manque quelque chose, ou j'ai le mauvais bout du bâton, ou je ne vois pas le bois pour les arbres. Quelqu'un peut-il me mettre sur la bonne voie?

Phillip B Oldham
la source
1
Si ce n'était pas une API aussi simple avec des méthodes de base, vous sentiriez-vous différent? Même un hangar doit résister à la neige.
JeffO

Réponses:

31

Le travail d'un client API distant consiste à émettre certains appels, ni plus, ni moins. Par conséquent, son test doit vérifier qu'il émet ces appels - ni plus, ni moins.

Bien sûr, si le fournisseur d'API modifie la sémantique de leurs réponses, votre système échouera en production. Mais ce n'est pas la faute de votre classe de client; c'est quelque chose qui ne peut être attrapé que dans les tests d'intégration. En vous fiant à un code indépendant de votre volonté, vous avez abandonné la possibilité de vérifier son exactitude au moyen de tests internes. C'était un compromis, et c'est le prix.

Cela dit, tester une classe composée uniquement de délégations dans une autre classe peut être une priorité basse, car le risque d'erreurs complexes est relativement faible. Mais cela vaut pour toutes les classes composées uniquement de lignes uniformes, cela n’a rien à voir avec l’appel du code d’un autre fournisseur.

Kilian Foth
la source
Mmm, pas sûr que je suis d'accord. Vous pouvez tester que l’ foo()appel soit appelé avant bar(), mais cela ne signifie pas qu’appeler foo()avant bar()est la bonne chose à faire; un test unitaire comme celui-là passerait même si le code était faux. Et si c'est tout ce que fait le client, il est relativement compliqué de configurer des simulacres qui vérifient si foo()un appel bar()est déjà effectué, ce qui peut être vérifié en jetant un coup d'œil rapide sur le code du client.
Doval
1
Vous pouvez vérifier qu'une add()méthode ajoute deux nombres correctement, mais cela ne signifie pas pour autant que l'ajout est la bonne chose à faire à ce stade de l'algorithme: le add()test unitaire réussira même si votre programme est erroné. Si c'est la mauvaise chose, votre levenshteinDistance()méthode est à blâmer, pas la add()méthode. C'est exactement pareil. Le fait que le code soit séparé en méthodes a toujours pour but que chaque méthode ne doit s’occuper que de corriger une chose.
Kilian Foth
3
Maintenant, je vois où nous ne sommes pas d’accord! Si vous comptez sur un magasin pour animaux de compagnie externe, cela signifie pour moi que votre système se termine à la limite HTTP. Par conséquent, les appels REST émis sont des sorties et sont soumis à des tests. Si vous considérez que l'animalerie fait partie de ce module, alors, oui, le modèle d'appels émis est un détail de la mise en œuvre, et un test unitaire n'a aucune activité à prescrire.
Kilian Foth
2
"Par conséquent, son test devrait vérifier qu'il émet ces appels" Je pense que c'est la perspective que je ne percevais pas. Merci!
Phillip B Oldham
1
Ainsi, par exemple, mon test unitaire pourrait vérifier que, compte tenu de certains paramètres, le corps de la requête à exécuter est le bon?
Maria Ines Parnisari
9

Réponse courte:

Toutes les méthodes doivent être testées à l'unité.

Longue réponse:

Oui. Ça vaut le coup.

Voici certaines choses que les tests unitaires sur ces méthodes d'appel d'API doivent tester:

  • Que vous transmettez des paramètres corrects ou corrects aux appels d'API.
  • Que vous répondiez en conséquence à certains types de données renvoyées par les API (modélisées ou non), par exemple, lorsque l'API renvoie une chaîne vide, votre méthode doit renvoyer une valeur par défaut (à titre d'exemple).
  • Que les méthodes de l'appelant se comportent correctement lorsque les appels d'API génèrent une erreur

Ce sont des choses que la méthode appelée fait qui peuvent être isolées lorsque je moque le service d'API et qu'en les testant correctement, vous vous assurez que les erreurs ne sont pas générées par une erreur dans le code client qui appelle l'API.

Tulains Córdova
la source
Vous dites "moqué ou pas" ... alors est-il possible de tester contre la vraie API? Puis-je appeler cela un test d'intégration même s'il ressemble à un test unitaire? Ou y a-t-il autre chose à appeler cela? J'adorerais tester que mon wrapper d'API fait ce qu'il dit, en quelque sorte ...
Dan Rosenstark
1
@DanRosenstark J'imagine que dans le cas où le service d'API n'est pas moqué, il s'agit d'un test d'intégration.
Tulains Córdova
Ne sauriez-vous pas en 5 secondes si vous récupérez correctement les données lorsque vous effectuez un appel à l'API? Étant donné que les alarmes d’API ne sont pas de véritables appels, le seul moyen d’échouer est qu’elles changent d’API. Dans ce cas, vos essais d'imitation seront couronnés de succès, mais les appels réels échoueront. Semble inutile
MattE
5

Ce ne sont pas des tests unitaires, car vous testez les entrées et les sorties de votre système, plutôt que des tests d'intégration limités.

Soyez très prudent lorsque vous dites "cela semble être un gaspillage d’efforts et que nous testons quelque chose qui ne peut pas vraiment échouer" . les échecs seront pires si vous n'avez pas de tests en place.

L’erreur que vous commettez ici est liée à l’invention des roues: il est très courant d’appeler des services distants et des API, il existe donc de très bons outils pour vous aider à le tester. La dernière fois que je travaillais sur une application connectée à des services distants, j'ai utilisé SoapUI.qui peut consulter un service et faire des appels fictifs à ce service ou se comporter comme une copie locale du serveur sur laquelle vous pouvez effectuer des tests et suivre les demandes et les réponses. La configuration a pris quelques minutes et, de même, a été très rapide à mettre à jour si l'interface distante était modifiée. Je ne l'ai pas utilisé dans un scénario REST, mais même si cela ne fonctionne pas bien pour cela (ou si quelqu'un lit cette réponse à l'avenir lorsqu'il existe de meilleurs outils), vous devriez être en mesure de trouver un outil qui peut être simulé. un service pour vous et quand vient le temps de déployer votre code, vous serez heureux de l'avoir fait.

glénatron
la source