2009-10-19 5 views
1

J'ai une classe appelée FooJob() qui s'exécute sur un service Windows WCF. Cette classe a seulement 2 méthodes publiques, le constructeur, et une méthode Run().Tester uniquement la méthode publique sur une classe de taille moyenne?

Lorsque les clients appellent mon service, un Dim une nouvelle instance de la classe d'emploi, passer certains paramètres à l'cteur, puis appelez Run() ...

Run() prendra les paramètres, faire logique, envoyer une demande (en temps réel) à un fournisseur de données externe, prendre la réponse, faire une logique métier, puis la mettre dans la base de données ...

Est-il sage d'écrire seulement un test unitaire (si même possible) sur la fonction Run()? Ou vais-je finir par me tuer ici? Dans ce cas, devrais-je forer dans les fonctions privées et tester les unités de la classe FooJob()? Mais alors, cela ne va-t-il pas «casser» le paradigme de «comportement de test seul»/interface publique que certains défendent dans TDD? Je sais que cela pourrait être une question vague, mais tout conseil/orientation ou des points dans la bonne direction seraient très appréciés.

Drew

Répondre

2

faire une certaine logique, envoyer un (temps réel) demande à un fournisseur de données à l'extérieur, prendre la réponse, faites une logique métier, puis le mettre dans la base de données

Le problème ici est que vous avez énuméré votre classe comme ayant de multiples responsabilités ... pour être vraiment unité testable, vous devez suivre le principe de la responsabilité unique. Vous devez extraire ces responsabilités dans des interfaces distinctes. Ensuite, vous pouvez tester vos implémentations de ces interfaces individuellement (en tant qu'unités). Si vous trouvez que vous ne pouvez pas facilement tester quelque chose que fait votre classe, une autre classe devrait probablement le faire.

Il semble que vous auriez besoin d'au moins les éléments suivants:

  1. Une interface pour votre logique métier.
  2. Une interface définissant la demande au fournisseur externe.
  3. Une interface pour votre référentiel de données.

Ensuite, vous pouvez tester cette logique métier, le processus de communication avec le fournisseur externe et le processus d'enregistrement dans votre base de données séparément. Vous pouvez ensuite simuler ces interfaces pour tester votre méthode Run(), en vous assurant simplement que les méthodes sont appelées comme vous le souhaitez.

Pour ce faire correctement, les dépendances de la classe (les interfaces définies ci-dessus) devraient idéalement être transmises à son constructeur (c'est-à-dire l'injection de dépendance), mais c'est une autre histoire.

+0

Merci ... Mais j'ai une question - à quel point sommes-nous trop techniques et construisons trop de classes, alors que nous pourrions simplement tester certaines fonctions privées? Y a-t-il une règle générale ici? Juste aller avec votre intestin ...? – dferraro

+0

Je vous conseille de jeter un oeil aux principes SOLID de la conception orientée objet (http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod), dont le principe de responsabilité unique est un. J'essaierais également de ne pas considérer la décomposition en plusieurs classes comme étant trop technique, car chaque classe devient plus simple et plus compréhensible. Je dirais que «si vous éprouvez le besoin de tester une méthode privée, ce devrait probablement être une autre classe» serait une règle empirique, ainsi que ce que j'ai dit plus haut au sujet d'avoir à énumérer les responsabilités d'une classe. – ColinD

+0

Je casse les classes jusqu'à ce qu'elles ne puissent plus être séparées. Si vous évitez les valeurs de retour et que vous pensez aux classes comme l'envoi de messages les uns aux autres, cela devient un peu plus facile à conceptualiser. Les micro-classes ont l'avantage d'être extrêmement faciles à comprendre, ainsi que le fait que l'ajout de nouveaux comportements se fait généralement en ajoutant plus de classes, ce qui signifie que vous pouvez laisser le code existant et testé seul. C'est une bonne chose. – kyoryu

1

La réponse simple est - cela dépend. J'ai écrit beaucoup de tests unitaires qui testent le comportement des méthodes privées; J'ai fait ceci pour que je puisse être heureux que j'ai couvert diverses entrées et scénarios contre les méthodes.

Maintenant, beaucoup de gens pensent que tester des méthodes privées est une mauvaise idée, car ce sont les méthodes publiques qui importent. J'ai eu cette idée, mais dans mon cas, la méthode publique pour ces appels privés était aussi une simple méthode Run(). La logique des méthodes privées incluait la lecture à partir de fichiers de configuration et l'exécution de tâches sur le système de fichiers, le tout «en coulisses». Si j'avais juste créé un test unitaire appelé Run() alors j'aurais senti que mes tests étaient incomplets. J'ai utilisé MSTest pour créer des accesseurs pour ma classe, afin que je puisse appeler les méthodes privées et créer divers scénarios (comme ce qui se passe quand je manque d'espace disque, etc.).

Je suppose que c'est à chacun leur propre avec ce test de méthode privée faire/ou ne pas faire d'argument. Mon conseil est que, si vous pensez que vos tests sont incomplets, en d'autres termes, nécessitent plus de couverture, alors je vous recommande de tester les méthodes privées.

2

Mon conseil serait de laisser vos tests aider à la conception de votre code. Si vous avez du mal à exécuter des instructions ou des fonctions, votre classe en fait trop. Suivez le principe de la responsabilité unique, ajoutez quelques interfaces (vous permettant de simuler les choses compliquées), peut-être même lire "Refactoring" de Fowler ou "Working With Legacy Code" de Feather, cela m'a appris plus que tout autre livre à ce jour .

1

Il semble que votre méthode d'exécution essaie d'en faire trop, je le sépare, mais si vous ne l'avez pas, la conception globale ne le permet pas.

J'envisagerais de protéger les membres internes puis d'hériter de la classe de votre classe de test pour les tester. Soyez prudent, même si je me suis heurté à des pièges car cela ne réinitialise pas l'état des classes, donc les méthodes Setup et TearDown sont essentielles.

0

Merci à tous pour vos commentaires. Je crois que vous avez raison - j'ai besoin de séparer en plusieurs classes séparées. C'est l'un des premiers projets que j'utilise en TDD, en ce sens que je n'ai pas du tout design de classe et que j'écris juste du code stub ... Je dois admettre que j'adore écrire du code comme ça et que je peux le justifier mangagment avec des années de résultats réussis soutenus est purement friggin awesome =). La seule chose qui m'inquiète, c'est le sur-engineering et la souffrance de class-bloat, alors que j'aurais pu écrire des tests unitaires contre mes méthodes privées ... Je suppose que le bon sens et les programmeurs doivent être utilisés ici ...?

Questions connexes