2010-08-13 5 views
3

Deux questions sur les tests unitaires.Quelques questions sur les tests unitaires

  1. J'ai écrit des tests unitaires pour un certain temps, mais ils sont généralement classes de test je l'avais déjà écrit. Récemment, j'ai lu an article (attention à un vieil article) qui dit vous devriez écrire des tests unitaires avant de commencer à écrire votre code .

    Est-ce que quelqu'un suit réellement cette méthodologie ? Il semble être une bonne idée sur le papier, mais en pratique, c'est ?

  2. Si vous écrivez des tests unitaires pour voir comment votre méthode gère les entrées mauvaises/malveillantes? Évidemment, vous voudrez écrire des tests sur des fonctions qui sont spécifiquement destinées à gérer les entrées "utilisateur" pour voir comment il gère les entrées mauvaises/malveillantes, mais qu'en est-il des fonctions qui ne devraient jamais recevoir ce type d'entrée? À quel moment tracez-vous la ligne?

Répondre

8

La méthodologie d'écriture des tests unitaires avant les classes est appelée Test-Driven Development (TDD) et a été popularisée par Kent Beck au début des années 2000. L'idée est que vous écrivez un test qui décrit les fonctionnalités dont vous avez besoin. Initialement, ce test échouera. Comme vous écrivez votre classe, le test passe. Vous refactorisez votre test pour ajouter plus de fonctionnalités souhaitées, puis refactorisez la classe pour faire passer ce nouveau test. Votre classe a atteint ses objectifs dès que les tests ont passé. Bien sûr, cela va au-delà des classes aussi.

En ce qui concerne les types de tests à écrire, cela dépend si vous testez une API publique ou une API privée. Les API publiques doivent avoir des tests plus complets écrits pour s'assurer que les entrées sont bien formées, en particulier si vous ne faites pas entièrement confiance aux utilisateurs de votre API. Les API privées (méthodes appelées uniquement par votre code) peuvent probablement s'en passer sans ces tests - je suppose que vous pouvez faire confiance à votre propre équipe de développement pour ne pas leur transmettre de mauvaises données.

+1

En fait, pour clarifier, vous n'écrivez TOUS vos tests à l'avance. Vous écrivez un test. Il échoue. Vous écrivez du code pour le faire passer. Vous modifiez ensuite votre test ou en écrivez un autre. Encore une fois, cela échoue. Écrivez le code. C'est un processus baptisé "Rouge, Vert, Refactor". – CaffGeek

+0

Merci pour cela. Je vais jeter cela dans ma réponse, juste pour plus de clarté. –

2

Écrire les tests unitaires en premier est une pratique courante. Un gros avantage est que vous n'écrivez pas seulement des tests que votre code va passer mais plutôt des tests qui définissent ce qui est important, ce que vous essayez d'accomplir, et ce que vous voulez vous assurer que cela n'arrivera pas. Cela peut vous aider à étoffer votre conception. En outre, vous pouvez vérifier le point avec des parties prenantes externes avant de coder.

En ce qui concerne les tests à écrire, c'est un peu subjectif en fonction du temps dont vous disposez. Je ne deviendrais pas fou code de dépistage pour les scénarios auxquels il ne sera jamais confronté. Cela dit, il est incroyable ce que l'entrée fait au code qui "ne le verra jamais". Donc, plus de tests sont meilleurs, mais il y a certainement des rendements décroissants à un moment donné.

Le langage que vous utilisez pour le codage. Les langages dynamiques requièrent plus de tests car le compilateur capture moins de problèmes et les bogues peuvent être plus difficiles à suivre (puisqu'ils peuvent se propager plus loin du problème d'entrée initial). Au moins, c'est mon opinion.

Cela fait également une différence d'où provient l'entrée. Le grand public devrait être considéré comme positivement malveillant (c.-à-d. Le Web), les employés devraient être considérés incompétents, et même les codeurs compagnons (et vous-même!) Devraient être supposés être au moins négligents. Mais le danger diminue à mesure que vous vous rapprochez de votre cercle intérieur.

+0

Comme l'a dit Chad, vous n'avez pas besoin d'écrire tous les tests imaginables à l'avance. Au lieu de cela, vous pouvez commencer avec un ensemble raisonnable de tests qui définissent la conception et la spécification, puis ajouter des tests si vous trouvez des échecs ou des vulnérabilités que vos tests actuels n'attrapent pas. Fondamentalement, la suite de tests est en développement tant que l'application est en service. – Justin

2

Test Driven Development est un concept assez répandu. L'idée de base est que vous essayez d'écrire uniquement du code qui est nécessaire pour satisfaire certaines exigences du logiciel. Donc, vous écrivez un test pour l'exigence, puis le code pour faire passer le test.

Personnellement, je n'utilise pas TDD, mais je connais des gens qui le font. Mes pensées personnelles sont qu'il est très utile si vous travaillez sur quelque chose qui est plus axé sur les applications, comme une base de données ou une interface utilisateur. Mais, pour quelque chose qui est plus lourd en algorithmes (comme un modèle de physique), je trouve que cela brise mon train de pensée et me gêne.

2

Est-ce que quelqu'un suit réellement cette méthodologie?

Oui.

Cela semble être une bonne idée sur papier, mais en pratique est-ce?

Oui.

Si vous écrivez des tests unitaires pour voir comment votre méthode gère les entrées mauvaises/malveillantes?

Oui.

Qu'en est-il des fonctions qui ne devraient jamais recevoir ce type d'entrée? À quel moment tracez-vous la ligne?

Lorsqu'il passe du logiciel à la psychose.

Vous pouvez - si vous le souhaitez - écrire des tests pour des situations impossibles. Cependant, vous perdez votre temps et celui de votre employeur de façon évidente.

Vous écrivez des tests pour les cas d'utilisation définis. Et c'est tout.

Vous ne créez pas de tests aléatoires en fonction de votre imagination.

Et si? Que se passe-t-il si les cas d'utilisation définis sont incomplets? Bummer. Vous écrivez des tests pour l'interface officielle, contractuelle et publique - et rien de plus. Et si la conception est inadéquate et que vous vous rendez compte que l'interface donnée est criblée de spécifications, de contradictions et de failles de sécurité incomplètes? Cela n'a rien à voir avec les tests. C'est juste de la programmation. La mauvaise conception est mauvaise conception.

Que se passe-t-il si un sociopathe malveillant prend votre code et l'utilise d'une manière qui dépasse (ou ne parvient pas à respecter) les spécifications définies? Bummer. Le sociopathe gagne. Ils ont pu mettre votre code dans la situation impossible que vous n'avez pas testée. Achetez-leur une bière pour être si intelligent.

+0

Et après que ces situations "impossibles" se produisent, vous ajoutez un test pour le recréer, il échouera. Ensuite, vous corrigez votre code. Et à l'avenir, vous avez maintenant testé l'impossible, et faites un test pour que l'impossible ne se reproduise plus. – CaffGeek

+0

Je ne suis pas d'accord avec votre approche "seulement ce que dit la spécification". Cela peut être approprié pour la programmation contractuelle, mais je pense que le développement de produits nécessite une approche plus proactive car il n'y a souvent pas de délimitation formelle entre la conception et le développement. Dans la plupart de mon travail, si le design est mauvais, je n'ai personne à blâmer, mais moi-même et mes collègues. – ChrisH

+0

@ChrisH: "pas de délimitation formelle entre design et développement". Faux. Vos cas de test ** sont ** votre conception. C'est pourquoi TDD est si efficace. –

0

Il y a déjà un assez bon groupe de réponses, mais je voudrais dire encore penser à la question numéro 2.

Si vous faites votre code unittest « guidée par les données », il ne devrait pas d'importance si le code teste les entrées "mauvaises" ou "bonnes". Ce qui compte, c'est que vous ayez un ensemble de données assez important qui couvre les deux.

1

Il existe une différence de mentalité entre test-before et test-after.Écrire des tests avant est une forme de design, en ce sens que vous concevez l'interface de votre code et définissez le comportement attendu. Lorsque vous écrivez ensuite du code qui réussit les tests, cela valide votre conception. Et à la fin du développement, vous avez déjà une série de tests déjà en place! Avec le test-après, vous devez faire attention à éviter le piège de l'écriture des tests que votre code existant va passer. C'est un objectif différent, et vous n'en obtenez pas autant que la version test-before.

+0

Le piège que vous mentionnez dans le deuxième paragraphe est exactement pourquoi c'est une si mauvaise idée d'écrire vos tests par la suite. Je ne suis pas anale quant à la couverture complète de mes tests unitaires, mais si je vais écrire un test, je l'écrirai * toujours * avant le code. Sinon, il est trop facile de tomber dans le piège de l'ingénierie inverse de vos méthodes pour garantir que les tests passent toujours. – kubi

+0

@kubi En effet. C'est quelque chose que j'ai réalisé une fois que j'ai commencé à faire du TDD. –