7
votes

Unité teste une grande méthode

Après le développement axé sur les tests.

J'ai récemment mis en place un algorithme (A *) nécessitant une interface propre. En nettoyant tout ce que je veux, c'est quelques propriétés et une seule méthode de recherche.

Ce que j'ai trouvé dur teste la méthode de recherche. Il contient environ cinq étapes mais je suis essentiellement obligé de coder cette méthode dans une grande partie qui rend les choses difficiles.

Y a-t-il des conseils pour cela?

Modifier

J'utilise C #. Non, je n'ai pas le code à la main pour le moment. Mon problème s'appuie dans le fait qu'un test ne passe que après la mise en œuvre de l'ensemble de la méthode de recherche - plutôt qu'une étape de l'algorithme. J'ai naturellement refoulé le code après, mais il était implémensifi que j'ai trouvé dur.


2 commentaires

Êtes-vous capable de poster votre code?


Je viens d'avoir une idée de la courtoisie du TextTest. J'aurais dû utiliser un simulacre. Ensuite, vous avez simplement une suite de tests qui vérifient à chaque étape de la méthode de recherche, les cinq étapes de l'algorithme sont effectuées. Cela fonctionnerait-il?


5 Réponses :


-1
votes

Vous pouvez envisager de textest ( http://texttest.carmen.se/ ) comme moyen de Test "sous l'interface".

Il vous permet de vérifier le comportement en examinant les données enregistrées pour vérifier le comportement, plutôt que sur des tests purement black-box sur les arguments et les résultats de la méthode.

Disclaimer: J'ai entendu une présentation sur le TextTest et examiné les documents, mais je n'ai pas encore eu le temps de l'essayer dans une application sérieuse.


2 commentaires

-1 L'ensemble des tests de l'unité est de tester le comportement, non de la mise en œuvre. Vous voulez être capable de modifier la mise en œuvre tout en étant sûre que le comportement n'est pas affecté.


Le comportement se produit à plusieurs niveaux.



5
votes

Réfulteur Votre grande méthode en méthodes privées plus petites. Utilisez la réflexion ou un autre mécanisme disponible dans votre langue, pour tester les méthodes plus petites de manière indépendante. Le pire des cas - si vous n'avez pas accès à la réflexion ou à vos amis, faites les méthodes protégées et que votre classe de test hérite de la classe principale afin qu'elle puisse y avoir accès.

update : Je devrais également préciser que le refactoring simplement sur des méthodes privées n'implique pas nécessairement que vous devez créer des tests spécifiques à ces méthodes. Si vous testez minutieusement les méthodes publiques qui s'appuient sur les méthodes privées, vous n'avez peut-être pas besoin de tester directement les méthodes privées. C'est probablement le cas général. Il y a des moments où il est logique de tester des méthodes privées directement (disons quand il simplifie ou réduit le nombre de cas de test nécessaires aux méthodes publiques), mais je ne considérerais pas qu'il est nécessaire de créer des tests simplement parce que vous refacteur à un privé Méthode Mise en œuvre.


5 commentaires

L'odeur de méthode longue est l'une des odeurs de code canonique. Les idées de correction de la condition sont à C2.com/cgi/wiki?LongMethodsmell


Lors de la lecture plus étroite de la remarque de TVANFosson, je me méfierais extrêmement sur l'introduction de la réflexion en tests unitaires.


@Wan, pourquoi? Vous n'utilisez que la réflexion comme mécanisme pour invoquer la méthode privée pour ne rien changer de la classe. De nombreux cadres / IDes ont la fonctionnalité pour créer automatiquement des accesseurs pour faire exactement cela.


Je ne pense pas que ce soit un problème en soi, mais cela rend le test assez fragile lorsque quelqu'un pouvait raisonnablement renommer une méthode privée et ne pas s'attendre à ce que rien ne se casse (y compris des tests d'unités). Personnellement, j'irais la route protégée / remplacée (c'est-à-dire le double test spécifique).


@Finnnk - Compte tenu des outils de refactorisation dans l'IDE que j'utilise, vs, je ne m'inquiéterais pas de cela trop. Si votre IDE ne prend pas en charge le refactoring, ce serait plutôt une préoccupation, mais vous le découvririez assez rapidement.



14
votes

Si vos marches sont suffisamment grandes (ou sont significatives à part entière), vous devriez envisager de les déléguer à d'autres classes plus petites et tester l'interaction entre votre classe et elles. Par exemple, si vous avez une étape d'analyse suivie d'une étape de tri suivie d'une étape de recherche, il pourrait être significatif d'avoir une classe d'analyseur, une classe de trieur, etc. Vous utiliseriez alors TDD sur chacun de ceux-ci.

aucune idée de la langue que vous utilisez, mais si vous êtes dans le monde .Net, vous pouvez rendre ces classes internes, puis les exposer à votre classe de test avec "Internals visible pour" qui les garderait cachée.

Si les étapes sont petites et sans signification à leurs propres suggestions, les suggestions de TVanfosson sont la voie à suivre.


0 commentaires

1
votes

Je suppose qu'un * désigne l'algorithme de recherche (par exemple, http: // fr. wikipedia.org/wiki/a*_search_algorithm ). Si oui, je comprends votre problème car nous avons des exigences similaires. Voici l'algorithme WP, et je vais commenter ci-dessous:


Pseudo code xxx

Le jeu fermé peut être omis (céder un algorithme de recherche d'arbres) si une solution est garantie ou si l'algorithme est adapté de manière à ce que de nouveaux nœuds soient ajoutés. à l'ensemble ouvert uniquement s'ils ont une valeur F inférieure à celle de toute itération précédente.


Premièrement, et je ne suis pas frivole, cela dépend si vous comprenez l'algorithme - ça sonne comme si vous faites. Il serait également possible de transcrire l'algorithme ci-dessus - en espérant qu'il fonctionnait) et lui donner un certain nombre de tests. C'est ce que je ferais comme je soupçonne que les auteurs de WP sont meilleurs que moi !. Les tests à grande échelle exerceraient des cas de bord tels que aucun nœud, un nœud, deux nœuds + sans bord, etc. Si elles ont tous passé, je dormirais heureux. Mais s'ils ont échoué, il n'y a pas d'autre choix que de comprendre l'algorithme.

Si oui, je pense que vous devez construire des tests pour les structures de données. Ce sont (au moins) ensemble, distance, score, etc. Vous devez créer ces objets et les tester. Quelle est la distance attendue pour le cas 1,2,3 ... Ecrire des tests. Quel est l'effet d'ajouter A à Set Z? a besoin d'un test. Pour cet algorithme, vous devez tester heuristique_estimate_of_distance et ainsi de suite. C'est beaucoup de travail.

Une approche peut être de trouver une implémentation dans une autre langue et de l'interroger pour trouver les valeurs dans les structures de données. Bien sûr, si vous modifiez l'algorithme que vous êtes seul!

Il y a une chose encore pire que ceci - algorithmes numériques. Matrices de diagonalisation - obtenez-nous les bonnes réponses. J'ai travaillé avec un scientifique écrit 3ème matrices dérivées - cela me terrifierait ...


0 commentaires

2
votes

Une chose importante à retenir lorsque vous employez TDD est que les tests n'ont pas besoin de vivre pour toujours.

Dans votre exemple, vous savez que vous allez fournir une interface propre et une grande partie de l'opération sera déléguée à des méthodes privées. Je pense que c'est l'hypothèse que ces méthodes doivent être créées comme privées et rester de cette façon, cela provoque la plus grande peine. Aussi l'hypothèse que les tests doivent rester autour une fois que vous les avez développées.

Mon conseil pour ce scénario serait de:

  • Esquissez le squelette de la grande méthode en termes de nouvelles méthodes, vous avez donc une série d'étapes qui ont du sens à tester individuellement.
  • Faites ces nouvelles méthodes publiques par défaut et commencez à les développer à l'aide de TDD.
  • Ensuite, une fois que toutes les pièces ont testé, écrivez un autre qui teste la méthode totale . S'assurer que si l'une des parties plus petites et déléguées est brisée, ce nouveau test échouera.
  • À ce stade, la grande méthode fonctionne et est couverte par des tests, vous pouvez maintenant commencer à refacteur. Je recommanderais, comme Finnnk , essayant d'extraire le plus petit méthodes en classes de leur propre. Si cela n'a pas de sens, ou si cela prendrait trop de temps, je recommanderais quelque chose d'autre peut ne pas être d'accord avec: Changez les petites méthodes en privées et supprimer les tests pour eux. < / li>

    Le résultat est que vous avez utilisé TDD pour créer l'ensemble de la méthode, la méthode est toujours couverte par les tests et l'API est exactement celle que vous souhaitez présenter.

    Beaucoup de confusion provient de l'idée qu'une fois que vous avez écrit un test, vous devez toujours le garder et ce n'est pas nécessairement le cas. Toutefois, si vous êtes sentimental, il existe des moyens des tests unitaires pour des méthodes privées peut être atteint dans Java , peut-être il y a peut-être des constructions similaires dans c #.


2 commentaires

Suppression de tests semble être une mauvaise idée ... L'un des grands avantages à créer des tests est qu'il vous aide à savoir que les modifications ne cassent pas le code de travail précédemment.


@Andrew: Vous avez manqué le point. Avant de supprimer l'un des tests des plus petits unités, vous écrivez des tests qui exécutent la plus grande unité. Celles-ci testent les conditions du contrat public sans connaissance des petites parties. Les tests de l'unité plus importants se briseront toujours si l'une des pièces plus petites est modifiée et ne correspond pas aux conditions du contrat public. Donc, ils auraient toujours le bénéfice de vous faire savoir que les changements brisent auparavant du code de travail. Avez-vous mal lu ou avez-vous recommandé de réécrire la réponse pour faire ce point plus clair?