1
votes

Comment puis-je tester si une méthode privée d'une classe est appelée ou non avec rhino mock?

Je suis assez nouveau en C # et je me moque aussi de rhinocéros. J'ai cherché et trouvé des sujets similaires avec ma question, mais je n'ai pas trouvé de solution appropriée.

J'essaie de comprendre si la méthode privée est appelée ou non dans mon test unitaire. J'utilise rhinocéros, j'ai lu de nombreux fichiers à ce sujet, certains disent simplement que le spécificateur d'accès de la méthode passe de privé à public, mais je ne peux pas changer le code source. J'ai essayé de lier le fichier source à mon projet de test mais cela ne change pas.

    private CalculateClass sut;
    private Result result; 

    [SetUp]
    public void Setup()
    {
      result = MockRepository.GenerateStub<Result>();
      sut = new CalculateClass();
    }

    [TearDown]
    public void TearDown()
    {

    }

    [Test]
    public void test()
    {     
        sut.Stub(stub => stub.calculateItems(Arg<Result>.Is.Anything, Arg<string>.Is.Anything));

        sut.calculateItems();

        sut.AssertWasCalled(stub => stub.calculateItems(Arg<Result>.Is.Anything, Arg<string>.Is.Anything));
    }

Comme vous le voyez dans le code ci-dessus, j'ai deux méthodes qui ont exactement le même nom, CalculateItems, mais une publique n'a pas de paramètre, une privée a deux paramètres. J'essaie de comprendre quand j'appelle une méthode publique dans mon unittest, la méthode privée est-elle appelée?

  public void calculateItems()
    {
        var result = new Result(fileName, ip, localPath, remotePath);

        calculateItems(result, nameOfString);
    }

    private void calculateItems(Result result, string nameOfString )

Dans mon unittest, je prends une telle erreur qui dit "Aucune méthode de surcharge pour CalculateItems ne prend deux arguments". Existe-t-il un moyen de le tester sans aucune modification du code source?


0 commentaires

3 Réponses :


5
votes

Vous testez la mauvaise chose. Les méthodes privées sont privées. Ils ne concernent pas la consommation de code et les tests unitaires consomment du code comme les autres.

Dans vos tests, vous testez et validez la fonctionnalité orientée vers l'extérieur du composant. Ses détails d'implémentation internes ne sont pas pertinents pour les tests. Tout ce qui compte pour les tests est de savoir si l'opération invoquée produit les résultats attendus.

La question que vous devez vous poser est donc ... Quels sont les résultats attendus lors de l'appel de cette opération?:

calculateItems()

Il ne renvoie rien, alors que fait ? Quel état modifie-t-il d'une manière ou d'une autre? C'est ce que votre test doit observer, pas les détails d'implémentation mais le résultat observable. (Et si l'opération n'a aucun résultat observable, alors il n'y a pas de différence entre "réussi" ou "échoué" donc il n'y a rien à tester.)

Nous ne pouvons pas voir les détails de votre code, mais il est possible que le résultat observable soit entièrement couplé à un autre composant. Si tel est le cas, cet autre composant est une dépendance pour cette opération et le but du test unitaire est de simuler cette dépendance afin que l'opération puisse être testée indépendamment de la dépendance. Le composant peut alors avoir besoin d'être modifié afin qu'une dépendance soit fournie plutôt que contrôlée en interne. (Ceci est appelé le Principe d'inversion de dépendance .)


A noter également ...

mais je ne peux pas changer le code source

C'est un problème complètement distinct. Si vous ne pouvez vraiment pas changer le code source, alors la valeur de ces tests est considérablement réduite et peut-être complètement éliminée. Si un test échoue, que pouvez-vous faire? Rien. Parce que vous ne pouvez pas changer le code. Alors, que testez-vous?

Gardez à l'esprit qu'il est non seulement possible mais malheureusement très courant pour les programmeurs d'écrire du code qui ne peut être significatif unité testée. Si ce code vous a été fourni par quelqu'un d'autre et qu'il vous est interdit de le modifier pour une raison non technique, il sera de la responsabilité de cette autre personne de corriger le code. «Corriger» peut inclure «rendre possible un test unitaire significatif». (Ou, honnêtement, ils devraient le tester unitaire. Pas vous.)


2 commentaires

Bonne explication de cela.


Merci beaucoup pour la réponse.



0
votes

Si votre méthode publique appelle votre méthode privée, la même chose se produira dans vos tests. Les tests ne sont rien de plus que du code qui peut être exécuté et débogué et vous pouvez essayer cela, alors voyez ce qui se passe.

Les méthodes privées ne peuvent pas être testées directement mais elles peuvent être testées via leurs appelants publics, ce que vous faites, donc tout va bien. Que ce soit une bonne idée d'avoir une configuration comme celle-ci, c'est une toute autre histoire, mais je ne m'y attarde pas maintenant.

Voyons maintenant ce que vous testez réellement.

Les tests unitaires ne doivent pas avoir une connaissance approfondie du code qu'ils testent. La raison en est que vous devriez avoir des entrées et des sorties et que vous ne devriez pas vous soucier de ce qui se passe entre les deux.

Si vous refactorisez le code et éliminez la méthode privée, votre test serait interrompu, même si vos entrées et sorties de votre méthode publique restent les mêmes. Ce n'est pas une bonne position, c'est ce que nous appelons les tests fragiles.

Ajoutez donc vos tests fonctionnels autour de la méthode publique, vérifiez que vous obtenez le chapeau que vous attendez et ne vous inquiétez pas si elle appelle votre méthode privée ou non.


0 commentaires

0
votes

Lorsque vous dites que vous avez besoin de savoir si vos méthodes privées sont appelées, cela peut avoir deux interprétations différentes:

  1. Vous voulez vous assurer que la méthode privée est appelée dans un test particulier, ce qui en fait un critère de réussite pour ce test même.

  2. Vous voulez savoir si la méthode privée est appelée du tout, par l'un de vos cas de test. Cela pourrait vous intéresser parce que vous voulez être sûr que la méthode privée est couverte par votre suite de tests, ou comme vous l'avez dit, simplement pour comprendre ce qui se passe réellement dans votre code.

Concernant la deuxième interprétation: Si vous voulez comprendre ce qui se passe dans le code, une bonne approche consiste à utiliser un débogueur et à parcourir le code pour voir quelle fonction est appelée. Comme je ne suis pas un expert C # ici, je ne peux recommander aucun outil de débogage spécifique, mais trouver des recommandations à ce sujet sur le Web ne devrait pas être difficile. Cette approche répondrait à vos exigences de ne pas nécessiter de modifications du code source

Une autre possibilité, en particulier si vous souhaitez savoir si votre fonction privée est couverte par les tests, est d'utiliser un outil de couverture de test pour C #. L'outil de couverture vous montrerait si la méthode privée a été appelée ou non. Encore une fois, cela ne nécessiterait aucune modification du code source.

Concernant la première interprétation de votre question: Si vous voulez tester qu'une fonction privat est appelée dans le cadre du critère de succès de votre test, vous le faites de préférence avec des tests utilisant l'API publique. Ensuite, dans ces tests, vous devriez être en mesure de juger si la fonction privée est appelée en raison de l'effet que la fonction privée a sur le résultat du test.

Et, contrairement à d'autres opinions, vous devriez tester l'implémentation. L'objectif principal des tests unitaires est de trouver les bogues dans le code. Différentes implémentations ont des bogues différents. C'est pourquoi les gens utilisent également des outils de couverture, pour voir s'ils ont couvert le code de leur implémentation. Et, la couverture ne suffit pas, vous devez également vérifier les cas limites des expressions, etc. mais pas toujours), mais ce sont des objectifs secondaires par rapport à l'objectif de trouver tous les bogues.


0 commentaires