Test unitaire d'une méthode qui appelle une autre méthode

Quelle est la meilleure façon de tester une méthode qui appelle plusieurs méthodes, par exemple:

modify(string value)
{
    if(value.Length > 5)  replaceit(value);

    else changeit(value);
}

Ce pseudo code a une méthode modify qui (actuellement) appelle replaceit() ou changeit(). J'ai déjà écrit des tests pour replaceit et changeit, donc écrire un nouveau test pour modify sera 99% le même ensemble de code. Je dois le tester pensé parce qu'il peut changer dans le futur.

Puis-je copier coller le code de test existant? Déplacer le code de test vers une fonction commune? D'autres idées? Je ne suis pas sûr de la meilleure pratique ici.

46
demandé sur Anton Rudeshko 2008-12-12 20:48:46

12 réponses

Il s'agit d'un test classique basé sur l'état par rapport au scénario de test basé sur le comportement.

Dans cet exemple ridiculement simple, tester la sortie est bien. À un moment donné, vous rencontrerez des tests où l'inspection de l'état après l'exécution est compliquée. Au lieu de cela, vous voulez vérifier le comportement (par exemple, vérifier que changeit a été appelé avec une valeur spécifique).

À ce stade, vous devriez probablement regarder dans un cadre d'objet fictif comme Rhino.Mock (. net) ou Mockito (Java) et commencer à écrire plus de code basé sur l'interface.

31
répondu Eric Nicholson 2008-12-12 18:28:22

Vous avez un certain nombre d'options. Lequel est le meilleur dépend des détails qui ne sont pas clairs de votre question.

  • test modify comme s'il s'agissait d'une méthode non liée. Avantage: il pourrait à un moment donné devenir un.
  • testez simplement que vous avez bien la déclaration if. Autrement dit, testez juste assez pour que les tests vous forcent à écrire l'implémentation dont vous avez besoin (où l'appel replaceit et changeit est juste l'implémentation la plus simple qui pourrait éventuellement fonctionner. Si vous êtes pratiquer TDD, cela devrait venir naturellement à vous. Avantage: couverture élevée d'essai sans effort beaucoup dupliqué.
  • Subclass et Override Method (c'est une technique de rupture de dépendance du livre "travailler efficacement avec le code hérité"): testez la méthode sur une sous-classe que vous introduisez uniquement à des fins de test, qui remplace replaceit et changeit avec des réponses en conserve ou pour définir des variables de détection (variables qui indiquent si la méthode la juste valeur(s)). Avantage: peut-être simplifier vos tests (ou non), parfois même rendre les tests possibles.
  • extrait une nouvelle classe pour les méthodes replaceit et changeit, y compris une interface pour cette classe. Stub ou Mock cette interface lors du test modify. Avantage: pourrait à la fois rendre votre conception plus testable et mieux découplée/réutilisable en général (ou non).
13
répondu Ilja Preuß 2008-12-12 19:24:10

Si vous avez déjà testé replaceit() et changeit() indépendamment, alors la seule chose qu'il vous reste à tester est la condition if. Test modify() avec quelques valeurs pour s'assurer qu'il appelle la bonne fonction dans de bonnes conditions, (ces conditions étant null et Strings de longueur 4, 5, et 6 pour l'exemple de code que vous avez donné).

13
répondu Bill the Lizard 2016-08-08 11:02:15

Juste tester modify.

Modify est censé renvoyer certaines valeurs lorsqu'on lui donne certaines valeurs.

C'est sans importance comment modifier fait son travail - seulement qu'il ne son travail.

Et si, à l'avenir, vous changez modify pour utiliser des méthodes différentes( ou pas de méthodes), cela n'affecte pas, et ne devrait pas, et n'affectera pas vos tests.

Cela dit, testez également replaceit' and changeit`.

5
répondu Ian Boyd 2008-12-12 18:07:37

Par ordre de préférence

  1. modify (test) a juste 2 scénarios (chaque bras de l'if stmt), donc j'écrirais 2 tests pour modifier le formulaire.
    Si le résultat attendu de replaceit(valeur) est facile à déterminer..

.

public TestModifyIfValueLength..()
    {
      string expectedValue = .. ;// literal result of replaceit(value)
      Assert.Equals( expectedValue, modify("asd") );
    }
  1. si ce n'est pas le cas, envisagez d'utiliser un stub (utilisez la sous-classe et remplacez changeit, replaceit) pour vérifier que la méthode correcte a été appelée.
  2. si le talon est trop de travail, faire la chose fictive. Extraire une interface et configurer les attentes sur changeit, replaceit.

Hypothèses

  • Vous avez des tests pour replaceit (value) et changeit (value), qui testent (par exemple toutes les conditions aux limites pour) ces 2 méthodes de manière exhaustive.
  • replaceit() et changeit() sont des méthodes publiques.. Sinon, vous devriez envisager d'écrire des tests contre les méthodes publiques seulement. Vous devriez être libre de modifier / supprimer des méthodes privées sans que le code de test le sache.
4
répondu Gishu 2009-01-12 06:14:26

Qu'est-Ce que "le code de test" dans ce cas? Configuration et vérification des résultats? Si c'est le cas, je le refactoriserais dans une méthode différente et l'utiliserais à partir de chacun des tests. Je ne le ferais que s'il y en a une quantité significative - il y a un avantage de lisibilité à pouvoir voir tout ce qu'un test fait, juste en lisant le code de cette méthode.

Les méthodes de test compliquées me dérangent souvent pour commencer, pour être honnête-souvent, elles ne peuvent pas être évitées de manière réaliste, mais si vous Pouvez simplifiez-les, Cela vaut la peine de le faire.

3
répondu Jon Skeet 2008-12-12 17:56:06

Eh bien, non, votre code de test ne sera pas identique à 99%, car vous testez quelque chose de différent ici, à moins que replaceit, changeit et modify ne renvoient tous les mêmes valeurs.

Je ne sais pas pourquoi la difficulté. L'essai pour la méthode modify devrait être d'environ quatre lignes. Puisque vous testez déjà la fonctionnalité sous-jacente et tout ce que vous voulez faire est de vous assurer que cette méthode particulière ne casse pas, en écrivant un test qui teste les deux chemins de code possibles dans ce les valeurs attendues de retour de fonction devraient être suffisantes.

2
répondu TheSmurf 2008-12-12 17:54:55

Si vous avez déjà écrit des tests pour replaceit () et changeit (), le test de modify vérifierait simplement que différents résultats sont renvoyés en fonction de la valeur de 'value'. Cependant, vous allez simplement réimplémenter la logique de la méthode dans le test, ce qui est un peu absurde.

Dans ce cas, je ne testerais pas modifier jusqu'à ce qu'il ait une logique plus complexe, ou mieux - est utilisé par une autre méthode plus importante à tester.

2
répondu Eran Galperin 2008-12-12 17:57:40

Vous avez essentiellement besoin de 2 tests.

1) passer dans une chaîne comme "le renard brun rapide saute!"(longueur supérieure à cinq) s'assure que la valeur est affectée par replaceit(...)

2) passez une chaîne comme " Foo " (la longueur est inférieure à cinq) et assurez-vous que la valeur est affectée par changeit(...)

Test (en pseudo code) pourrait ressembler à ceci:

testLongValue() {
    string testValue = "A value longer than 5 chars";
    string expected = "Replaced!";
    string actual = modify(testValue);
    assertEqual(expected, actual);
}

testShortValue() {
    string testValue = "len4";
    string expected = "Changed!";
    string actual = modify(testValue);
    assertEqual(expected, actual);
}

Évidemment, je pourrais vous donner un exemple plus réaliste si je savais ce que replacit () et changeit () étaient censés faire, mais ceci devrait vous donner l'idée. Si elle mute la référence de valeur d'origine au lieu de la renvoyer, vous pouvez simplement utiliser testValue comme valeur réelle après l'appel.

2
répondu Justin Standard 2008-12-12 18:17:30

Lorsque vous testez des conditions aux limites telles que if (value.length > 5), Vous devez vous assurer que vos données de test contiennent des valeurs de value qui ont une longueur 4, 5, ou 6.

2
répondu Brian Matthews 2008-12-12 18:19:43

Vous pouvez créer une fonction à partir des méthodes et simuler ces fonctions. Ou, vous pouvez créer des méthodes virtuelles et en utilisant Rhino mocks-simulacre partiel, vous pouvez simuler ces méthodes virtuelles.

2
répondu Saravanan 2012-10-23 22:03:09

Identique à Justin Standard, plus passant {[0] } comme valeur (ce qui échouera évidemment pour l'extrait de code que vous nous donnez ;)) La règle de base pour les tests unitaires est "tester uniquement ce qui est spécifique à la méthode testée". Et il tout à fait ... rare d'avoir une méthode qui n'en appelle pas une autre.

0
répondu Olivier 2008-12-12 18:36:55