Je travaille sur un projet où les appels internes de classe sont habituels mais les résultats sont souvent des valeurs simples. Exemple ( pas de vrai code ):
public boolean findError(Set<Thing1> set1, Set<Thing2> set2) {
if (!checkFirstCondition(set1, set2)) {
return false;
}
if (!checkSecondCondition(set1, set2)) {
return false;
}
return true;
}
L'écriture de tests unitaires pour ce type de code est vraiment difficile car je veux juste tester le système de conditions et non l'implémentation des conditions réelles. (Je le fais dans des tests séparés.) En fait, il serait préférable de passer des fonctions qui implémentent les conditions et dans les tests, je fournis simplement des simulations. Le problème avec cette approche est le bruit: nous utilisons beaucoup de génériques .
Une solution de travail; cependant, il faut faire de l'objet testé un espion et se moquer des appels aux fonctions internes.
systemUnderTest = Mockito.spy(systemUnderTest);
doReturn(true).when(systemUnderTest).checkFirstCondition(....);
Le problème ici est que l'implémentation du SUT est effectivement modifiée et il peut être problématique de garder les tests synchronisés avec l'implémentation. Est-ce vrai? Existe-t-il une meilleure pratique pour éviter ce ravage d'appels de méthode interne?
Notez que nous parlons de parties d'un algorithme, donc le répartir en plusieurs classes peut ne pas être une décision souhaitée.
la source
Si les deux
findError()
etcheckFirstCondition()
etc. sont des méthodes publiques de votre classe, alorsfindError()
c'est effectivement une façade pour les fonctionnalités qui sont déjà disponibles à partir de la même API. Il n'y a rien de mal à cela, mais cela signifie que vous devez écrire des tests très similaires aux tests déjà existants. Cette duplication reflète simplement la duplication dans votre interface publique. Ce n'est pas une raison pour traiter cette méthode différemment des autres.la source
Les tests unitaires devraient tester le contrat; c'est la seule chose importante pour eux. Tester tout ce qui ne fait pas partie du contrat n'est pas seulement une perte de temps, c'est une source potentielle d'erreur. Chaque fois qu'un développeur modifie les tests lorsqu'il modifie un détail d'implémentation, des sonneries d'alarme doivent sonner; ce développeur peut (intentionnellement ou non) cacher ses erreurs. Tester délibérément les détails de l'implémentation force cette mauvaise habitude, ce qui rend plus probable le masquage des erreurs.
Les appels internes sont un détail d'implémentation et ne devraient être utiles que pour mesurer les performances . Ce qui n'est généralement pas le travail des tests unitaires.
la source
a
contient un appel à la méthodeb
dans la même classe, les tests dea
doivent inclure les tests deb
. Et il n'y a aucun moyen de changer cela tant qu'ilb
n'est pas passéa
en paramètre. Mais il n'y a pas d'autre solution, je vois.b
fait partie de l'interface publique, il doit quand même être testé. Si ce n'est pas le cas, il n'a pas besoin d'être testé. Si vous l'avez rendu public simplement parce que vous vouliez le tester, vous vous êtes trompé.Tout d'abord, je me demande ce qui est difficile à tester sur l'exemple de fonction que vous avez écrit? Pour autant que je sache, vous pouvez simplement passer diverses entrées et vérifier que la valeur booléenne correcte est renvoyée. Qu'est-ce que je rate?
En ce qui concerne les espions, le genre de tests dits "à boîte blanche" qui utilise des espions et des simulations représente des ordres de grandeur plus de travail à écrire, non seulement parce qu'il y a tellement plus de code de test à écrire, mais chaque fois que l'implémentation est changé, vous devez également changer les tests (même si l'interface reste la même). Et ce type de test est également moins fiable que les tests en boîte noire, car vous devez vous assurer que tout ce code de test supplémentaire est correct, et même si vous pouvez être sûr que les tests unitaires en boîte noire échoueront s'ils ne correspondent pas à l'interface , vous ne pouvez pas faire confiance à cela à propos du code utilisant trop de mocks parce que parfois le test ne teste même pas beaucoup de vrai code - seulement des mocks. Si les simulations sont incorrectes, il est probable que vos tests réussiront, mais votre code est toujours cassé.
Quiconque a de l'expérience avec les tests en boîte blanche peut vous dire qu'ils ont du mal à écrire et à maintenir. Couplés au fait qu'ils sont moins fiables, les tests en boîte blanche sont tout simplement bien inférieurs dans la plupart des cas.
la source