2009-05-05 12 views
1

Je suis un technicien TDD et je ne sais pas comment résoudre le problème suivant. J'ai assez grande classe qui génère un fichier texte dans un format spécifique, pour l'importation dans le système externe. Je vais refactoriser cette classe et je veux écrire des tests unitaires avant.Stratégie de refactoring pour la classe qui génère un fichier texte spécifique

À quoi ces tests devraient-ils ressembler? En fait, l'objectif principal - ne pas briser la structure du fichier. Mais cela ne signifie pas que je devrais comparer le contenu du fichier avant et après?

Répondre

1

Je pense que vous pourriez bénéficier d'un test que je hésite à appeler un « test unitaire » - bien que sans doute il teste le courant de production fichier texte « unité ». Cela exécuterait simplement le code actuel et ferait un diff entre sa sortie et un fichier "maître d'or" (que vous pourriez générer en exécutant le test une fois et en le copiant à l'endroit désigné). S'il y a beaucoup de comportement conditionnel dans le code, vous pouvez vouloir exécuter ceci avec plusieurs exemples, chacun étant un cas de test différent. Avec le code existant, par définition, tous les tests devraient passer.

Maintenant, commencez à refactoriser. Extraire une méthode - ou mieux, écrire un test pour une méthode que vous pouvez envisager d'extraire, un vrai test unitaire - extraire la méthode, et s'assurer que tous les tests, pour la nouvelle petite méthode et pour le plus grand système, passent toujours. Mousser, rincer, répéter. Les tests du système vous donnent un filet de sécurité qui vous permet d'avancer dans le refactoring en toute confiance; les tests unitaires pilotent la conception du nouveau code.

Il existe des bibliothèques disponibles pour faire ce genre de test plus facile (même si il est assez facile, même sans eux). Voir http://approvaltests.sourceforge.net/.

1

Dans un tel cas, j'utilise la stratégie suivante:

  • Ecrire un test pour chaque méthode (juste couvrant son comportement par défaut sans traitement des erreurs, etc.)

  • Exécuter un outil de couverture de code et trouve les blocs non couverts par les tests. Écrire des tests couvrant ces blocs.

  • Continuez jusqu'à ce que vous obtenez une couverture de code de plus de 80%

  • Démarrer refactoring la classe (la plupart du temps générer des classes plus petites après la séparation du principe de préoccupation). Utilisez le développement piloté par les tests pour écrire les nouvelles classes.

1

En fait, c'est un bon point de départ (en comparant une sortie bien connue à ce qui est généré par la classe actuelle). Si la classe de générateur unique peut produire des résultats différents, créez-en une pour chaque cas. Cela garantira que vous ne brisez pas votre classe de générateur actuelle.

Une chose qui pourrait vous aider est si vous avez le document de spécification pour la classe en cours. Vous pouvez l'utiliser comme base de votre effort de refactoring.

1

Si vous ne l'avez pas encore fait, procurez-vous une copie du livre de Michael Feathers "Working Effectively with Legacy Code". Tout est sur la façon d'ajouter des tests au code existant, ce qui est exactement ce que vous recherchez. Mais jusqu'à ce que vous ayez fini de lire le livre, je vous suggère de commencer par un test de régression: créez la classe, demandez-lui d'écrire le fichier sur le disque, puis comparez ce fichier à un fichier "bien connu" que vous avez caché dans votre référentiel source quelque part. Si elles ne correspondent pas, échouer le test.

Puis commencez à regarder les décisions intéressantes que votre classe prend. Voyez comment vous pouvez les tester. Peut-être que vous extrayez des conditions if compliquées dans des fonctions publiques qui retournent bool, et vous écrivez une batterie de tests pour prouver que, avec les bonnes entrées, cette fonction renvoie la bonne valeur. Peut-être que la génération d'une chaîne particulière a une logique intéressante; Commencez à le tester.

En chemin, vous pouvez trouver des objets qui veulent sortir. Par exemple, vous pouvez trouver que le code (ou les tests!) Serait plus simple s'il y avait une classe séparée qui génère une seule ligne de sortie. Vas-y avec. Tu as ton test de régression pour t'attraper si tu baises quoi que ce soit.

Travaillez sans relâche pour éliminer les dépendances (mais assurez-vous d'avoir un test de plus haut niveau, comme un test de régression, pour vous rattraper si vous faites des erreurs).Si votre classe crée son propre FileStream et écrit sur le système de fichiers, changez-le pour prendre un TextWriter dans son constructeur, afin que vous puissiez écrire des tests qui passent dans un StringWriter et ne jamais toucher au système de fichiers. Une fois cela fait, vous pouvez vous débarrasser de l'ancien test qui écrit un fichier sur le disque (mais seulement si vous ne l'avez pas cassé en essayant d'écrire le nouveau test!) Si votre classe a besoin d'une connexion à la base de données un test qui passe dans de fausses données. Etc.