Deux façons de réaliser des tests unitaires fiables

On pense que les tests unitaires ne sont pas nécessaires. Que seulement la moitié de la vérité est cachée en eux. Et cette véritable information sur le comportement du programme ne sera révélée que lorsque nous les collecterons dans un test d'intégration.

Il y a une raison à cela, mais les tests unitaires sont-ils vraiment incomplets et peuvent-ils être rendus plus fiables? Combien de raisons de leur incomplétude?

Supposons que nous ayons deux composants couverts par le test unitaire, Caller et Callee. L'appelant appelle Callee avec un argument et utilise en quelque sorte l'objet renvoyé. Chacun des composants a son propre ensemble de dépendances, que nous absorbons.

Combien de scénarios dans lesquels ces composants se comportent de manière inattendue lors de l'intégration?

Le premier scénario est un problème externe aux deux composants . Par exemple, ils dépendent tous deux de l'état de la base de données, de l'autorisation, des variables d'environnement, des variables globales, des cookies, des fichiers, etc. Juger cela est assez simple, car même dans les très gros programmes, il y a généralement un nombre limité de tels points de discorde.

Le problème peut être résolu, évidemment, soit par une refonte avec des dépendances réduites,
ou nous simulons directement une erreur possible dans un scénario de niveau supérieur, c'est-à-dire que nous introduisons le composant CallingStrategy (OffendingCaller, OffendedCallee) {} et simulons le crash de l'appelé et la gestion des erreurs dans CallingStrategy. Pour cela, les tests d'intégration ne sont pas requis, mais une compréhension est nécessaire que le comportement spécifique de l'un des composants présente un risque pour l'autre composant, et il serait bon d'isoler ce scénario dans un composant.

Deuxième scénario: le problème est dans l'interface des objets intégrables, c'est-à-dire un état inutile d'un des objets s'est infiltré dans un autre .

En fait, c'est une faille dans l'interface qui le permet. La solution au problème est également assez évidente - typage et rétrécissement des interfaces, validation précoce des paramètres.

Comme nous pouvons le voir, les deux raisons sont extrêmement courantes, mais il serait bon de dire clairement qu'il n'y en a pas d'autres.

Ainsi, si nous vérifions nos classes pour 1) l'état interne et 2) les dépendances externes, nous n'avons aucune raison de douter de la fiabilité des tests unitaires.

(Quelque part dans le coin, un programmeur fonctionnel pleure doucement avec les mots «je vous l'ai dit», mais pas à ce sujet pour le moment).

Mais nous pouvons simplement oublier ou manquer une sorte de dépendance!

Peut être grossièrement estimé. Supposons qu'il y ait dix scénarios dans chaque composant. Nous sautons un scénario sur dix. Par exemple, Callee retourne soudainement null et Caller reçoit soudainement une NullPointerException. Nous devons faire une erreur deux fois, ce qui signifie que la probabilité de tomber quelque part est de 1/100. Il est difficile d’imaginer que le scénario d’intégration des deux éléments le prouve. Pour de nombreux composants appelés séquentiellement dans le test d'intégration, la probabilité d'attraper certaines des erreurs augmente, ce qui signifie que plus la pile du test d'intégration est longue et plus il y a de scénarios, plus elle est justifiée.

(Les mathématiques réelles de l'accumulation d'erreurs sont, bien sûr, beaucoup plus compliquées, mais le résultat ne varie pas beaucoup).

Dans le processus de réalisation du test d'intégration, cependant, nous pouvons nous attendre à une augmentation significative du bruit provenant des dépendances brisées et au temps considérable consacré à la recherche d'un bogue, ils sont également proportionnels à la longueur de la pile.

Autrement dit, il s'avère que des tests d'intégration sont nécessaires si les tests unitaires sont mauvais ou manquants . Par exemple, lorsque seul un script valide est vérifié dans chaque test unitaire, lorsqu'ils utilisent des interfaces trop larges et n'analysent pas les dépendances générales.

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


All Articles