Un exemple d'échec que vous préféreriez éviter, est que l'objet testé utilise une couche de mise en cache mais ne conserve pas les données comme requis. Ensuite, si vous interrogez l'objet, le message "Ouais, j'ai le nouveau nom et l'adresse", mais vous voulez que le test échoue car il n'a pas réellement fait ce qu'il était censé faire.
Sinon (et en négligeant la violation de responsabilité unique), supposons qu'il soit nécessaire de conserver une version codée en UTF-8 de la chaîne dans un champ orienté octet, mais en fait, elle persiste avec Shift JIS. Un autre composant va lire la base de données et s'attend à voir UTF-8, d'où l'exigence. Ensuite, l'aller-retour à travers cet objet indiquera le nom et l'adresse corrects car il le reconvertira à partir de Shift JIS, mais l'erreur n'est pas détectée par votre test. Espérons que cela sera détecté par un test d'intégration ultérieur, mais l'objectif des tests unitaires est de détecter les problèmes plus tôt et de savoir exactement quel composant est responsable.
Si l'un d'entre eux ne fait pas ce qu'il est censé faire, son propre scénario de test échouera et nous pourrons le réparer et exécuter à nouveau la batterie de test.
Vous ne pouvez pas supposer cela, car si vous ne faites pas attention, vous écrivez un ensemble de tests mutuellement dépendants. Le "est-ce que ça sauve?" test appelle la méthode de sauvegarde testée, puis la méthode de chargement pour confirmer la sauvegarde. Le "charge-t-il?" test appelle la méthode save pour configurer le dispositif de test, puis la méthode de chargement testée pour vérifier le résultat. Les deux tests reposent sur l'exactitude de la méthode qu'ils ne testent pas, ce qui signifie qu'aucun des deux ne teste réellement l'exactitude de la méthode testée.
L'indice qu'il y a un problème ici est que deux tests supposés tester différentes unités font la même chose . Ils appellent tous deux un setter suivi d'un getter, puis vérifient que le résultat correspond à la valeur d'origine. Mais vous vouliez vérifier que le setter persiste dans les données, mais que la paire setter / getter fonctionne ensemble. Donc, vous savez que quelque chose ne va pas, il vous suffit de trouver quoi et de corriger les tests.
Si votre code est bien conçu pour les tests unitaires, vous avez au moins deux méthodes pour vérifier si les données ont bien été conservées correctement par la méthode testée:
simulez l'interface de base de données et demandez à votre simulacre d'enregistrer le fait que les fonctions appropriées ont été appelées, avec les valeurs attendues. Cela teste la méthode et fait le test unitaire classique.
transmettez-lui une base de données réelle avec exactement la même intention , pour enregistrer si les données ont été correctement conservées ou non. Mais plutôt que d'avoir une fonction fictive qui se contente de dire "ouais, j'ai les bonnes données", votre test lit directement dans la base de données et confirme que c'est correct. Ce n'est peut-être pas le test le plus pur possible, car tout un moteur de base de données est une très grosse chose à utiliser pour écrire une maquette glorifiée, avec plus de chance que j'oublie une certaine subtilité qui fait passer un test même si quelque chose ne va pas (par exemple, je ne devriez pas utiliser la même connexion de base de données pour lire que celle utilisée pour écrire, car je pourrais voir une transaction non validée). Mais il teste la bonne chose, et au moins vous savez que c'est précisément implémente toute l'interface de la base de données sans avoir à écrire de code factice!
Il s’agit donc d’un simple détail d’implémentation de test, que je lise les données de la base de données de test par JDBC ou que je moque la base de données. Quoi qu'il en soit, le fait est que je peux mieux tester l'unité en l'isolant que si je lui permettais de conspirer avec d'autres méthodes incorrectes de la même classe pour obtenir une apparence correcte, même en cas de problème. Par conséquent, je souhaite utiliser tout moyen pratique pour vérifier que les données correctes ont bien été conservées, en dehors de la confiance envers le composant dont je teste la méthode.
Si votre code n'est pas bien conçu pour les tests unitaires, vous n'avez peut-être pas le choix, car l'objet dont vous souhaitez tester la méthode risque de ne pas accepter la base de données en tant que dépendance injectée. Dans ce cas, la discussion sur le meilleur moyen d'isoler l'unité à tester passe à une discussion sur le degré de proximité possible pour isoler l'unité à tester. La conclusion est la même, cependant. Si vous pouvez éviter les complots entre unités défectueuses, alors vous le ferez, sous réserve du temps disponible et de tout ce que vous pensez qui serait plus efficace pour trouver des erreurs dans le code.