Test unitaire d'une méthode de vide

13

Afin de corriger un bogue dans une application, j'ai modifié une méthode nommée postLoginen ajoutant un appel à une méthode existante nommée getShoppingCart.

Code

protected void postLogin() {
  getShoppingCart();
}

Cependant, je ne sais pas quelle est la meilleure façon d'écrire un test unitaire postLogin.

Approche 1

Utilisez la vérification de Mockito pour simplement vérifier que la méthode a été appelée.

verify(mock).getShoppingCart();

Approche 2

Testez l'effet secondaire de l'appel de méthode en récupérant la valeur du panier de l'utilisateur.

AssertNotNull(user.getShoppingCart());

Une approche est-elle meilleure que l'autre?

UN B
la source
1
selon ce qui rend le test plus facile à comprendre et maintient le code propre. Si vous n'êtes pas sûr de la conception du test, cela POURRAIT également être un signe que la conception du code est désactivée. Assurez-vous que vous posez ces questions: " POURQUOI l' ajout de cet appel de méthode corrige-t-il le bogue? Est-ce la bonne façon de corriger ce bogue?"
Caleb
8
À moins que votre getShoppingCart()méthode n'ait des effets secondaires, vous n'avez pas besoin de vérifier qu'elle s'appelle. S'il a des effets secondaires, vous devriez vraiment changer son nom car les getXXX()méthodes devraient être idempotentes.
Jules
@Jules getNextValue? On pourrait dire que quelqu'un pourrait dire "Ne l'appelez pas un getter; changez le nom en nextValue", mais j'ai déjà vu getNextutilisé auparavant. Un meilleur exemple serait peut-être un objet représentant un électron; que se passe-t-il lorsque j'appelle getPosition? Ou pire,getPosition(); getVelocity();
Aaron

Réponses:

18

Je préfère généralement la méthode 2.

Pourquoi? Parce que vous voulez postLoginchanger un état de votre système, mais comment il accomplit cela (et quelles méthodes il appelle en interne pour cela) n'est qu'un détail d'implémentation, rien sur quoi votre test unitaire ne devrait faire d'hypothèses. Il vaut donc mieux faire votre test en vérifiant simplement l'état final.

Doc Brown
la source
4

Je changerais getShoppingCart en quelque chose comme initializeShoppingCart, le but de la méthode devrait être clair pour quiconque la lit sans avoir besoin de vérifier ce que fait la méthode et des effets secondaires comme celui-ci peuvent provoquer un comportement surprenant pour les utilisateurs de la méthode.

Si getShoppingCart est dans une autre classe et qu'il est déjà testé unitaire, j'utiliserais l'approche 1 - pas besoin de tester à nouveau ce qui a déjà été testé. Dans ce cas, nous sommes sûrs que getShoppingCart fonctionne correctement et nous voulons seulement nous assurer qu'il est appelé à partir de postLogin, donc si quelqu'un à l'avenir supprime cet appel, le test échouera.

Si getShoppingCart est une méthode privée qui ne peut pas être testée par elle-même, j'utiliserais l'approche 2, pour m'assurer que lorsque postLogin est appelé, la fonctionnalité souhaitée de getShoppingCart est exécutée comme prévu.

Nastya S
la source
1

Lorsque vous testez un appel de fonction (vide ou non) qui a un effet secondaire, il est plus complet de tester que l'effet secondaire se produit non seulement, mais de vérifier que l'effet secondaire (sortie système ou changement d'état) est celui souhaité.

hotpaw2
la source
1
Bien que cela soit vrai, il convient également de considérer que les détails de l'effet secondaire qui se produit pourraient faire partie de l'état interne d'un autre module, et qu'en vérifiant ces détails, vous coupleriez votre test non seulement au module qui c'est le test mais aussi cet autre module qui pourrait conduire à des tests fragiles si ces détails sont susceptibles de changer. Se moquer de l'interface entre les modules permet d'éviter ce problème.
Jules
0

Je ne discuterai pas de votre conception, mais dans votre cas, j'opterais pour la première approche car le test unitaire sert à tester quelles méthodes font techniquement quel que soit leur travail dans le domaine, c'est-à-dire ce que fait votre méthode postLogin? Techniquement, cela appelle getShoppingCarddonc vous devez tester qui appelle vraiment getShoppingCard, je créerais également un autre test pour getShoppingCardtester ce qu'il fait et s'il a des effets secondaires, je le vérifierai dans ce nouveau test.

La VloZ Merrill
la source
0

Vous avez un bogue dans postLogin. La première chose à faire est donc de créer un test unitaire qui, lors de l'appel à postLogin sans l'ensemble d'informations attendu, "échouera".

De l'idée ci-dessus, une autre alternative parmi les 2 proposées est d'injecter les informations sur le panier en tant que paramètre. Si vous ne disposez pas des informations correctes, vous lancez une exception non vérifiée. Cela montrera clairement que sans les détails corrects, votre méthode est vouée à l'échec.

Cela nécessitera un petit changement où le client appelant le postLogin en ce moment doit également transmettre les informations du panier. Pour moi, c'est toujours cohérent maintenant que vous voyez qu'ils sont couplés. Ce couplage sera effectué par l'appelant.

Ensuite, vous n'auriez même pas besoin de tester getShoppingCart dans postLogin car la vraie méthode testée est postLogin. C'est celui qui a le bogue et le seul qui nécessite une correction et une validation appropriées. Avec la dépendance injectée, vous pourrez le tester facilement dans des conditions différentes et confirmer qu'aucune erreur n'est levée.

gumol
la source