Question

Alors que j'ai des tests unitaires pour la plupart écrit le code que je l'ai fait, je ne ai récemment obtenu mes mains sur une copie de TDD par exemple par Kent Beck. J'ai toujours regretté certaines décisions de conception que j'ai fait, car ils ont empêché l'application d'être « testable ». Je lis le livre et alors que certaines d'entre elles semble étranger, je sentais que je pouvais le gérer et a décidé de l'essayer sur mon projet actuel qui est essentiellement un système client / serveur sur lequel les deux pièces communiquent via. USB. Un sur le gadget et l'autre sur l'hôte. L'application est en Python.

J'ai commencé et très vite empêtré dans un désordre de réécritures et des tests minuscules qui je me suis dit plus tard ne pas tester vraiment quoi que ce soit. J'ai jeté la plupart d'entre eux et et ont maintenant une application de travail pour lequel les tests ont tous coagulé en seulement 2.

Sur la base de mes expériences, j'ai quelques questions que je voudrais poser. J'ai gagné quelques informations Nouveau à TDD: y at-il des exemples d'applications avec des tests pour montrer comment faire TDD mais ont des questions spécifiques que je voudrais des réponses à / discussion?.

  1. Kent Beck utilise une liste qu'il ajoute et frappe à partir pour guider le processus de développement. Comment faites-vous une telle liste? J'ai eu d'abord quelques éléments comme « serveur devrait démarrer », « serveur doit abandonner si le canal ne sont pas disponibles », etc., mais ils se sont mélangés et enfin maintenant, c'est juste quelque chose comme « client devrait être en mesure de se connecter au serveur » (qui démarrage du serveur subsumé etc.).
  2. Comment gérez-vous réécritures? J'ai d'abord choisi un système semi-duplex basé sur les canaux nommés afin que je puisse développer la logique d'application sur ma propre machine, puis ajouter plus tard, la partie de communication USB. Il les a déplacés pour devenir une chose à base de socket, puis déplacé d'utiliser des raw sockets à l'aide du module SocketServer Python. Chaque fois que les choses ont changé, je trouve que je devais réécrire une partie considérable des tests qui était ennuyeux. J'avais pensé que les tests seraient un guide un peu invariables au cours de mon développement. Ils ont juste l'impression d'être plus de code à manipuler.
  3. Je besoin d'un client et un serveur pour communiquer à travers le canal de tester chaque côté. Je pouvais se moquer de l'un des côtés pour tester l'autre mais ne serait pas testé toute la chaîne et je crains que je manquerais ça. Ce nui à tout le rythme rouge / vert / refactoring. Est-ce juste un manque d'expérience ou que je fais quelque chose de mal?
  4. Le « faux jusqu'à ce que vous le faites » m'a laissé avec beaucoup de code désordre que je plus tard passé beaucoup de temps à factoriser et nettoyer. Est-ce la façon dont les choses fonctionnent?
  5. A la fin de la session, j'ai maintenant mon client et le serveur en cours d'exécution avec environ 3 ou 4 tests unitaires. Il m'a fallu environ une semaine pour le faire. Je pense que je aurais pu le faire en un jour si j'utilisais les tests unitaires après chemin de code. Je ne vois pas le gain.

Je cherche des commentaires et des conseils de personnes qui ont mis en œuvre de grands projets non triviales complètement (ou presque complètement) en utilisant cette méthode. Il me semble logique de suivre la voie après J'ai quelque chose déjà en cours d'exécution et que vous voulez ajouter une nouvelle fonctionnalité, mais le faire à partir de zéro semble fastidieux et ne vaut pas l'effort.

P.S. :. S'il vous plaît laissez-moi savoir si cela devrait être la communauté wiki et je vais marquer comme ça

Mise à jour 0 : Toutes les réponses étaient également utiles. J'ai choisi celui que je l'ai fait parce qu'il a résonné avec mes expériences les plus.

Mise à jour 1 : pratique pratique pratique

Était-ce utile?

La solution

En tant que commentaire préliminaire, TDD prend la pratique. Quand je regarde en arrière les essais que j'ai écrit quand j'ai commencé TDD, je vois beaucoup de problèmes, comme quand je regarde le code que j'ai écrit il y a quelques années. Continuer à le faire, et comme vous commencez à reconnaître un bon code de mal, les mêmes choses vont se passer avec vos tests - avec patience.

  

Comment faites-vous une telle liste? je   avait d'abord quelques éléments comme « serveur   devrait démarrer « » serveur doit abandonner   si le canal est non disponible » etc., mais   ils se sont mélangés et enfin maintenant, il est   juste quelque chose comme « client devrait être   capable de se connecter au serveur "

« La liste » peut être assez informel (qui est le cas dans le livre de Beck), mais lorsque vous vous déplacez dans la fabrication des articles en tests, essayez d'écrire les déclarations dans un « [Quand quelque chose arrive à ce] puis [cette condition devrait être vrai sur ce] » format. Cela vous forcera à réfléchir davantage sur ce que vous êtes en train de vérifier, comment vous le vérifier et se traduit directement par des tests - ou si elle ne le fait pas, il devrait vous donner un indice sur lequel morceau de fonctionnalité est manquante. Pensez cas / scénario d'utilisation. Par exemple « serveur devrait démarrer » ne sait pas, parce que personne ne lance une action.

  

Chaque fois que les choses ont changé, je trouve que   Je devais réécrire des parties importantes de   les tests de ce qui était ennuyeux. je voudrais   compris que les tests seraient un   Guide peu invariables pendant mon   développement. Ils se sentaient comme plus juste   code pour gérer.

D'abord, oui, les tests sont plus de code, et nécessite un entretien - et l'écriture de tests maintenables prend la pratique. Je suis d'accord avec S. Lott, si vous avez besoin de changer vos tests beaucoup, vous êtes probablement tester « trop profond ». Idéalement, vous voulez tester au niveau de l'interface publique, ce qui est susceptible de changer, et non au niveau du détail de la mise en œuvre, ce qui pourrait évoluer. Mais une partie de l'exercice est de venir avec un design, donc vous devriez vous attendre à obtenir une partie de mal et doivent se déplacer / refactoriser vos tests ainsi.

  

Je pourrais se moquer de l'un des côtés pour tester   l'autre mais tout le canal   ne serait pas testé et je crains que   Je me manqueraient cela.

Pas tout à fait sûr que l'un. Du son de celui-ci, à l'aide d'une maquette était la bonne idée: prendre un côté, se moquer de l'autre, et vérifier que chaque côté fonctionne, en supposant que l'autre est mis en œuvre correctement. Test de l'essai ensemble du système est ensemble d'intégration, que vous voulez aussi faire, mais il est généralement pas partie du processus TDD.

  

Le « faux jusqu'à ce que vous le rendre » m'a laissé   avec beaucoup de code désordre que je plus tard   passé beaucoup de temps à factoriser et   nettoyer. Est-ce la façon dont les choses fonctionnent?

Vous devez passer beaucoup de temps refactoring tout en faisant TDD. D'autre part, lorsque vous faux, il est temporaire, et votre prochaine étape immédiate devrait être de non-semblant. En général, vous ne devriez pas avoir plusieurs tests en passant parce que vous feint il -. Vous devriez concentrer sur une seule pièce à la fois, et de travailler sur la refactorisation ASAP

  

Je pense que je aurais pu le faire en un jour   si j'utilisais les tests unitaires après   chemin de code. Je ne vois pas le gain.

Encore une fois, il faut de la pratique, et vous devriez obtenir plus rapidement au fil du temps. En outre, parfois TDD est plus fructueux que d'autres, je trouve que dans certaines situations, quand je sais exactement le code que je veux écrire, il est juste plus rapide d'écrire une bonne partie du code, puis écrire des tests.
En plus de Beck, un livre que j'ai apprécié est l'art de tests unitaires, par Roy Osherove. Ce n'est pas un livre TDD, et il est orienté vers .Net, mais vous voudrez peut-être lui donner un look de toute façon: une bonne partie est sur la façon d'écrire des tests maintenables, la qualité des tests et des questions connexes. J'ai trouvé que le livre a résonné avec mon expérience après avoir épreuves écrites et parfois eu du mal à le faire droit ...
Donc, mon conseil est, ne pas jeter les towel trop vite, et lui donner un peu de temps. Vous pouvez également donner un coup de feu sur quelque chose plus facile - les choses tests communication liée au serveur ne semble pas le plus facile de commencer par projet

Autres conseils

  
      
  1. Kent Beck utilise une liste ... enfin maintenant, il est juste quelque chose comme « client devrait être en mesure de se connecter au serveur » (qui démarrage serveur subsumé etc.).
  2.   

Souvent, une mauvaise pratique.

Des essais séparés pour chaque couche séparée de l'architecture sont bonnes.

Tests consolidés ont tendance à obscurcir les questions d'architecture.

Cependant, tester les fonctions que publiques. Toutes les fonctions.

Et ne pas investir beaucoup de temps à optimiser vos tests. La redondance dans les tests ne fait pas mal autant qu'il fait dans l'application de travail. Si les choses changent et un test fonctionne, mais une autre pause de test, peut-être alors vous pouvez factoriser vos tests. Pas avant.

  

2. Comment gérez-vous réécritures? ... Je trouve que je devais réécrire une partie considérable des tests.

Vous testez à un niveau de détail trop bas. Testez l'interface la plus externe, public, visible. La partie qui est censé être immuable.

Oui, le changement architectural important implique un changement de contrôle significatif.

Le code de test est de savoir comment vous prouver les choses fonctionnent. Il est presque aussi important que l'application elle-même. Oui, il est plus de code. Oui, vous devez le gérer.

  

3. Je avais besoin d'un client et un serveur pour communiquer à travers le canal de tester chaque côté. Je pouvais se moquer de l'un des côtés pour tester l'autre mais tout le canal ne sera pas testé ...

Il existe des tests unitaires. Avec simulacres.

Il existe des tests d'intégration, qui testent la chose.

Ne pas les confondre.

Vous pouvez utiliser des outils de tests unitaires pour faire des tests d'intégration, mais ils sont des choses différentes.

Et vous devez faire les deux.

  

4. Le « faux jusqu'à ce que vous le rendre » m'a laissé avec beaucoup de code désordre que je plus tard passé beaucoup de temps à factoriser et nettoyer. Est-ce la façon dont les choses fonctionnent?

Oui. C'est exactement comment cela fonctionne. À long terme, certaines personnes trouvent cela plus efficace que de forcer leur cerveau en essayant de faire toute la conception à l'avant. Certaines personnes n'aiment pas et veulent faire toute la conception à l'avant; vous êtes libre de faire beaucoup de conception à l'avant si vous voulez.

J'ai trouvé que refactoring est une bonne chose et le design à l'avant est trop dur. Peut-être parce que j'ai été le codage depuis près de 40 ans et mon cerveau s'use.

  

5. Je ne vois pas le gain.

Tous les vrais génies trouvent que les tests les ralentit.

Le reste d'entre nous ne peut pas être que notre code fonctionne jusqu'à ce que nous avons un ensemble complet de tests prouver que cela fonctionne.

Si vous n'avez pas besoin preuve que votre code fonctionne, vous n'avez pas besoin d'être essayées.

  

Q. Kent Beck utilise une liste qu'il ajoute et frappe à partir pour guider le processus de développement. Comment faites-vous une telle liste? J'ai eu d'abord quelques éléments comme « serveur devrait démarrer », « serveur doit abandonner si le canal ne sont pas disponibles », etc., mais ils se sont mélangés et enfin maintenant, c'est juste quelque chose comme « client devrait être en mesure de se connecter au serveur » (qui démarrage du serveur subsumé etc.).

Je commence par choisir tout ce que je pourrais vérifier. Dans votre exemple, vous avez choisi « démarrage du serveur ».

Server starts

Maintenant, je cherche un test plus simple que je pourrais vouloir écrire. Quelque chose avec moins de variations, et moins de pièces en mouvement. Je pourrais envisager « correctement serveur configuré », par exemple.

Configured server correctly
Server starts

Vraiment, bien que, « serveur démarre » dépend « correctement serveur configuré », donc je fais ce lien clair.

Configured server correctly
Server starts if configured correctly

Maintenant, je regarde les variations. Je demande: « Qu'est-ce qui pourrait mal tourner? » Je pourrais configurer le serveur de manière incorrecte. Combien de façons différentes que la matière? Chacun de ces fait un test. Comment le serveur ne démarre pas même si je configuré correctement? Chaque cas de ce fait un test.

  

Q. Comment gérez-vous réécritures? J'ai d'abord choisi un système semi-duplex basé sur les canaux nommés afin que je puisse développer la logique d'application sur ma propre machine, puis ajouter plus tard, la partie de communication USB. Il les a déplacés pour devenir une chose à base de socket, puis déplacé d'utiliser des raw sockets à l'aide du module SocketServer Python. Chaque fois que les choses ont changé, je trouve que je devais réécrire une partie considérable des tests qui était ennuyeux. J'avais pensé que les tests seraient un guide un peu invariables au cours de mon développement. Ils ont juste l'impression d'être plus du code pour gérer.

Quand je change le comportement, je trouve raisonnable de changer les essais, et même de les changer d'abord! Si je dois changer des tests qui ne vérifient pas directement le comportement que je suis en train de changer, cependant, c'est un signe que mes tests dépendent trop de comportements différents. Ce sont des tests d'intégration, ce qui je pense sont une escroquerie. (Google "Les tests d'intégration sont une escroquerie")

  

Q. Je avais besoin d'un client et un serveur pour communiquer à travers le canal de tester chaque côté. Je pouvais se moquer de l'un des côtés pour tester l'autre mais ne serait pas testé toute la chaîne et je crains que je manquerais ça. Ce nui à tout le rythme rouge / vert / refactoring. Est-ce juste un manque d'expérience ou que je fais quelque chose de mal?

Si je construis un client, un serveur et un canal, puis j'essaie de vérifier chacun dans l'isolement. Je commence par le client, et quand je test-drive, je décide comment le serveur et le canal doivent se comporter. Ensuite, je mets en œuvre le canal et le serveur chacun pour correspondre au comportement que j'ai besoin. Lors de la vérification du client, je STUB le canal; lors de la vérification du serveur, je me moque du canal; lors de la vérification du canal, je STUB et simulé à la fois client et serveur. J'espère que cela fait sens pour vous, puisque je dois faire des hypothèses sérieuses quant à la nature de ce client, serveur et canal.

  

Q. Le « faux jusqu'à ce que vous le rendre » m'a laissé avec beaucoup de code désordre que je plus tard passé beaucoup de temps à factoriser et nettoyer. Est-ce la façon dont les choses fonctionnent?

Si vous laissez obtenir très salissant votre code « truquer » avant de le nettoyer, alors vous pourriez avoir passé trop longtemps faire semblant. Cela dit, je trouve que même si je finis nettoyage plus code avec TDD, le rythme global se sent beaucoup mieux. Cela vient de la pratique.

  

Q. A la fin de la session, j'ai maintenant mon client et le serveur en cours d'exécution avec environ 3 ou 4 tests unitaires. Il m'a fallu environ une semaine pour le faire. Je pense que je aurais pu le faire en un jour si j'utilisais les tests unitaires après chemin de code. Je ne vois pas le gain.

Je dois dire que si votre client et le serveur sont très, très simple, vous avez besoin de plus de 3 ou 4 essais chacunpour les vérifier de manière approfondie. Je suppose que vos tests vérifient (ou au moins exécuter) un certain nombre de comportements différents à la fois, et qui pourraient expliquer l'effort qu'il a fallu pour les écrire.

En outre, ne mesurent pas la courbe d'apprentissage. Ma première expérience TDD consistait à réécrire la valeur de travail de 3 mois 9, 14 heures par jour. J'ai eu 125 tests qui ont pris 12 minutes pour courir. Je ne savais pas ce que je faisais, et je me sentais lent, mais on avait l'impression régulière, et les résultats ont été fantastiques. Je essentiellement re-écrit en 3 semaines ce qui à l'origine ont 3 mois pour se tromper. Si je l'ai écrit maintenant, je pourrais probablement le faire dans 3-5 jours. La différence? Ma suite de tests aurait 500 tests qui prennent 1-2 secondes pour courir. Cela est venu avec la pratique.

En tant que programmeur novice, la chose que je trouve la plus délicate sur le développement piloté par les tests a été l'idée que le test devrait venir en premier.

Pour le novice, ce n'est pas vraiment vrai. La conception vient en premier. (interfaces, des objets et des classes, méthodes, tout ce qui est approprié à votre langue.) Ensuite, vous écrivez vos tests à ce sujet. Ensuite, vous écrivez le code qui fait des choses.

Il a été un moment que je regardais le livre, mais Beck semble écrire comme si la conception du code se produit juste une sorte de inconsciemment dans votre tête. Pour les programmeurs expérimentés, cela peut être vrai, mais pour noobs comme moi, Nuh-uh.

J'ai trouvé les premiers chapitres de code complet vraiment utile pour réfléchir à la conception. Ils mettent l'accent sur le fait que votre conception pourrait bien changer, même une fois que vous êtes en bas au niveau Nitty Gritty de mise en œuvre. Lorsque cela se produit, vous pouvez bien avoir à réécrire vos tests, car ils étaient basés sur les mêmes hypothèses que votre conception.

Le codage est difficile. Allons faire les courses.

Pour un point, voir une question J'ai demandé un certain temps concernant votre premier point.

Au lieu de traiter les autres points à leur tour, je vais offrir quelques conseils mondiale. Entraine toi. Il m'a fallu un bon moment et quelques projets « » (louches personnels cependant) pour obtenir TDD réelle. Juste Google pour des raisons beaucoup plus convaincantes sur les raisons TDD est si bon.

Malgré les tests de conduite la conception de mon code, je reçois toujours un tableau blanc et griffonner sur une certaine conception. De là, au moins vous avez une idée de ce que vous êtes censé faire. Ensuite, je produis la liste des tests par appareil que je pense que je dois. Une fois que vous commencez à travailler, plus de fonctionnalités et des tests sont ajoutés à la liste.

Une chose qui se démarque de votre question est l'acte de réécriture de vos tests. Cela sonne comme vous effectuez des tests de comportement, plutôt que de l'État. En d'autres termes, les tests semblent trop étroitement liés à votre code. Ainsi, un simple changement qui n'a pas d'effet la sortie brisera des tests. Les tests unitaires (au moins bon de tests unitaires) aussi, est une compétence à maîtriser.

Je recommande Google Blog Test assez fortement parce que certains des articles là-bas fait mes tests pour TDD projets beaucoup mieux.

Les canaux nommés ont été mis derrière l'interface droite, changer la façon dont cette interface est mise en oeuvre (de canaux nommés à des prises à une autre bibliothèque sockets) ne teste que devrait d'impact pour le composant qui implémente cette interface. Donc, couper les choses plus / Conclure autrement ont aidé ... Cette interface les prises sont à l'origine évoluera probablement.

J'ai commencé à faire TDD il y a peut-être 6 mois? Je suis toujours moi-même l'apprentissage. Je peux dire au fil du temps mes tests et le code ont obtenu beaucoup mieux, donc le garder. Je recommande vraiment le livre XUnit design patterns aussi bien.

  

Comment faites-vous une telle liste à ajouter à   et biffer de guider la   processus de développement? J'avais d'abord une   quelques articles comme « serveur devrait commencer   up « » serveur doit abandonner si le canal   n'est pas disponible »

Les produits dans les listes TDD TODO sont grain plus fin que cela, ils visent à tester un comportement d'une seule méthode, par exemple:

  • test réussi connexion client
  • test de type d'erreur de connexion client 1
  • test de type d'erreur de connexion client 2
  • test réussi communication client
  • test de communication client échoue sans être connecté

Vous pouvez construire une liste de tests pour chaque exemple que vous avez donné (positives et négatives). De plus, lorsque les tests unitaires que vous n'établissez aucune connexion entre le serveur et le client. Vous invoquez juste des méthodes d'isolation, ... Cela répond à la question 3.

  

Comment gérez-vous réécritures?

Si les tests de comportement pour les tests unitaires et non la mise en œuvre, ils ne doivent pas être réécrite. Si le code de test unitaire crée vraiment un tube nommé pour communiquer avec le code de production et, il est évident que les essais doivent être modifiés lors du passage du tuyau à la prise. Les tests unitaires doivent rester à l'écart des ressources externes tels que les systèmes de fichiers, réseaux, bases de données, car ils sont lents, peuvent être indisponibles ... voir ces règles de tests unitaires .

Ceci implique la fonction du plus bas niveau ne sont pas testé unitairement, ils seront testés avec des tests d'intégration, où le système est testé de bout en bout.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top