2010-07-27 5 views
1

En ces jours je suis en train de coder des structures de données en Java. Beaucoup d'entre eux (sinon tous) offrent une interface très simple (ajouter, contenir, supprimer) mais sous le capot il y a des algorithmes non triviaux. Comment puis-je utiliser la technique tdd dans une telle situation?tdd avec des algorithmes non triviaux

Je pense que le problème est que tdd (et en général le test unitaire) consiste à tester les interfaces et non les implémentations. Ai-je raison? Comment puis-je faire face à cela?

Si vous connaissez une technique pour gérer ce cas, s'il vous plaît faites le moi savoir.

Nous vous remercions de votre aide.

Répondre

6

Vous avez raison de dire que TDD consiste à tester les interfaces, et non l'implémentation. Cela dit, pourquoi voulez-vous tester la mise en œuvre réelle? Le point est que si vous testez suffisamment l'interface, l'implémentation n'a pas d'importance.

Lorsque vous trouvez un bogue dans l'implémentation, cela signifie qu'il viole quelque part l'interface que vous exposez au monde extérieur. Vous devez le suivre jusqu'à l'endroit où il viole l'interface. C'est là que vous écrivez votre cas de test.

+0

Si je ne teste que l'interface dans ce cas, je n'ai aucune aide dans la construction de ma classe et l'écriture de mes méthodes.En pratique, je annule les avantages de tdd. Tu ne penses pas? – TheSENDER

+0

Rien ne vous empêche d'écrire des tests pour des méthodes d'implémentation internes comme 'merge()' ou 'resizeArray()', mais sachez que lorsque vous faites cela, vos tests deviennent plus fragiles. –

+0

En outre, si vous vous assurez que vos tests se trouvent dans le même package, vous pouvez le faire en protégeant les objets, c'est-à-dire en les masquant dans le monde réel. –

0

Le test de l'interface est nettement supérieur au test de l'implémentation. Plus tard, lorsque vous refactoriserez l'implémentation, vos tests seront toujours valides. Si vous estimez que vos méthodes sont trop complexes pour effectuer un test unitaire adéquat, c'est peut-être une indication que vous avez besoin de refactoriser votre code et de le décomposer en plusieurs méthodes plus petites (potentiellement privées) qui peuvent être testées séparément.

+0

D'accord, sauf pour (potentiellement privé) je dirais: méthodes publiques sur une autre classe utilisée par la classe d'origine. –

+0

@WW: C'est certainement une option à considérer. Mon opinion est que cela dépend de la réutilisation que vous attendez de la nouvelle méthode. S'il a le potentiel d'être utile ailleurs, rendez-le public sur une autre classe. Sinon, rendez-le privé. Comme le premier instinct de l'affiche était d'écrire une longue méthode, je supposais qu'elle n'aurait pas beaucoup de valeur ailleurs. Cependant, je suis d'accord que cela devrait être réévalué lors du refactoring. – dbyrne

0

Pour tester si une mise en œuvre contient certaines restrictions (par exemple: nombre de comparaisons, performances, etc.), vous pouvez TDD ces contraintes en utilisant des tests.

Je trouve cette conversation twitter très perspicace: http://twitoaster.com/kentbeck/brunopedroso-i-think-you-could-tdd-quicksort-youd-need-assertions-about-the-of-comparisons-ways-to-incrementally-improve-the-count/

Il parle de cette idée: TDDing une sorte rapide. Nous savons qu'un tri rapide est plus rapide qu'un tri à bulles. Les deux algorithmes donneront la même sortie (une collection triée), mais ils ont des contraintes différentes .

Ainsi, vous ajoutez explicitement les contraintes de votre algorithme dans vos tests (vous devez évidemment tester si votre algorithme fait ce que vous attendez de lui). Je suis d'accord que dans cet exemple, vous êtes quelque chose que vous connaissez déjà la réponse. Cependant, si vous devez trouver un algorithme complexe, vous n'allez probablement pas le TDD complètement. Mais les tests et les tests de contraintes vous aideront à savoir si vous avez trouvé la réponse ou non.

+0

Cela semble être une bonne idée. Vous testez l'algorithme sans trop vous soucier des détails de l'implémentation. Que pensez-vous que c'est la meilleure façon de le coder? – TheSENDER

+0

Pour être honnête, quand je dois coder ces types d'algorithmes, j'écris habituellement les tests pour voir si cela fonctionne. Si j'ai le sentiment que cela peut être amélioré et qu'il doit être amélioré, je vais le profiler, puis écrire des tests principalement sur les performances. Je n'ai jamais implémenté un algorithme comme je l'ai posté sur le lien, mais cela pourrait fonctionner. Cependant, je ne crois pas que des algorithmes révolutionnaires puissent être découverts de cette façon. Vous avez besoin de solides connaissances en mathématiques, les tests sont là simplement pour vous aider, pas pour le faire fonctionner. –

+0

Lien mort maintenant. Je suis sur mon téléphone ou je le réparerais :) –

0

J'ai trouvé l'exemple TDD/BDD dans RSpec livre très utile - http://www.pragprog.com/titles/achbd/the-rspec-book cela pourrait être quelque chose orienté rails mais dans le livre l'auteur va de la définition du problème, à l'identification des cas de test simples aux cas complexes dans un manière. L'exemple de ce livre concerne le développement d'un jeu et sa progression vers la réussite de tous les tests.

Cela peut également vous être utile car vous parlez d'interfaces et le BDD consiste à tester le comportement de l'application (dans votre algorithme de cas).

2

Si votre implémentation est complexe, il serait judicieux de la décomposer en modules plus petits. Ces modules plus petits auraient alors leur propre interface, que vous testeriez à l'unité. Par exemple, si vous résolvez le Sudoku en effectuant une recherche en profondeur, il serait rentable de développer séparément un algorithme de recherche en profondeur et un algorithme d'énumération de position Sudoku. Je ai blogué à ce sujet il ya un certain temps: http://matteo.vaccari.name/blog/archives/416