Qu'est - ce qu'un test unitaire , vraiment? Et y a-t-il vraiment une si grande dichotomie en jeu ici?
Nous travaillons dans un domaine où la lecture littéralement un bit après la fin d'un tampon peut totalement planter un programme, ou le faire produire un résultat totalement inexact, ou comme en témoigne le récent bogue TLS "HeartBleed", étendre un système censé être sécurisé à l'échelle ouvert sans produire de preuve directe de la faille.
Il est impossible d'éliminer toute complexité de ces systèmes. Mais notre travail consiste, dans la mesure du possible, à minimiser et à gérer cette complexité.
Un test unitaire est-il un test qui confirme, par exemple, qu'une réservation a bien été publiée dans trois systèmes différents, une entrée de journal est créée et une confirmation par e-mail est envoyée?
Je vais dire non . C'est un test d' intégration . Et ceux-ci ont certainement leur place, mais ils sont aussi un sujet différent.
Un test d'intégration fonctionne pour confirmer la fonction globale d'une «fonctionnalité» entière. Mais le code derrière cette fonctionnalité doit être décomposé en blocs de construction simples et testables, alias «unités».
Un test unitaire devrait donc avoir une portée très limitée.
Ce qui implique que le code testé par le test unitaire devrait avoir une portée très limitée.
Ce qui implique en outre que l'un des piliers d'une bonne conception consiste à décomposer votre problème complexe en morceaux plus petits et à usage unique (dans la mesure du possible) qui peuvent être testés relativement isolés les uns des autres.
Vous vous retrouvez avec un système constitué de composants de base fiables, et vous savez si l'une de ces unités fondamentales de code casse parce que vous avez écrit des tests simples, petits et à portée limitée pour vous dire exactement cela.
Dans de nombreux cas, vous devriez aussi probablement avoir plusieurs tests par unité. Les tests eux-mêmes doivent être simples, testant un et un seul comportement dans la mesure du possible.
La notion de «test unitaire» testant une logique non triviale, élaborée et complexe est, je pense, un peu un oxymore.
Donc, si ce genre de panne délibérée de la conception a eu lieu, comment un test unitaire pourrait-il soudainement commencer à produire des faux positifs, à moins que la fonction de base de l'unité de code testée n'ait changé? Et si cela s'est produit, vous feriez mieux de croire qu'il y a des effets d'entraînement non évidents en jeu. Votre test cassé, celui qui semble produire un faux positif, vous avertit en fait que certains changements ont brisé un cercle plus large de dépendances dans la base de code, et qu'il doit être examiné et corrigé.
Certaines de ces unités (beaucoup d'entre elles) peuvent avoir besoin d'être testées en utilisant des objets fictifs, mais cela ne signifie pas que vous devez écrire des tests plus complexes ou plus élaborés.
Pour en revenir à mon exemple artificiel d'un système de réservation, vous ne pouvez vraiment pas être l' envoi de demandes hors d'une base de données de réservation en direct ou un service tiers (ou même une instance « dev » de celui - ci) chaque fois que vous unité tester votre code.
Vous utilisez donc des mocks qui présentent le même contrat d'interface. Les tests peuvent ensuite valider le comportement d'un morceau de code déterministe relativement petit. Vert tout au long du tableau vous indique ensuite que les blocs qui composent votre fondation ne sont pas brisés.
Mais la logique des tests unitaires individuels eux-mêmes reste aussi simple que possible.