Le code dupliqué est une odeur dans le code de test unitaire autant que dans un autre code. Si vous avez du code dupliqué dans les tests, il est plus difficile de refactoriser le code d'implémentation car vous avez un nombre disproportionné de tests à mettre à jour. Les tests doivent vous aider à refactoriser en toute confiance, plutôt que d'être un lourd fardeau qui empêche votre travail sur le code testé.
Si la duplication est en cours de configuration, envisagez d'utiliser davantage la setUp
méthode ou de fournir des méthodes de création plus (ou plus flexibles) .
Si la duplication est dans le code manipulant le SUT, alors demandez-vous pourquoi plusieurs tests dits «unitaires» exercent exactement la même fonctionnalité.
Si la duplication se trouve dans les assertions, vous avez peut-être besoin d' assertions personnalisées . Par exemple, si plusieurs tests ont une chaîne d'assertions comme:
assertEqual('Joe', person.getFirstName())
assertEqual('Bloggs', person.getLastName())
assertEqual(23, person.getAge())
Alors peut-être avez-vous besoin d'une seule assertPersonEqual
méthode pour pouvoir écrire assertPersonEqual(Person('Joe', 'Bloggs', 23), person)
. (Ou peut-être avez-vous simplement besoin de surcharger l'opérateur d'égalité Person
.)
Comme vous l'avez mentionné, il est important que le code de test soit lisible. En particulier, il est important que l' intention d'un test soit claire. Je trouve que si de nombreux tests se ressemblent pour la plupart (par exemple, les trois quarts des lignes sont identiques ou pratiquement identiques), il est difficile de repérer et de reconnaître les différences significatives sans les lire attentivement et les comparer. Je trouve donc que la refactorisation pour supprimer la duplication contribue à la lisibilité, car chaque ligne de chaque méthode de test est directement pertinente par rapport à l'objectif du test. C'est beaucoup plus utile pour le lecteur qu'une combinaison aléatoire de lignes directement pertinentes et de lignes qui ne sont que des passe-partout.
Cela dit, les tests exercent parfois des situations complexes qui sont similaires mais toujours significativement différentes, et il est difficile de trouver un bon moyen de réduire la duplication. Faites preuve de bon sens: si vous pensez que les tests sont lisibles et que leur intention est claire, et que vous êtes à l'aise avec le fait d'avoir peut-être besoin de mettre à jour plus qu'un nombre théoriquement minimal de tests lors de la refactorisation du code invoqué par les tests, acceptez l'imperfection et déplacez-vous sur quelque chose de plus productif. Vous pouvez toujours revenir et refactoriser les tests plus tard, lorsque l'inspiration vous frappe!
La lisibilité est plus importante pour les tests. Si un test échoue, vous voulez que le problème soit évident. Le développeur ne devrait pas avoir à parcourir beaucoup de code de test fortement factorisé pour déterminer exactement ce qui a échoué. Vous ne voulez pas que votre code de test devienne si complexe que vous deviez écrire des tests de test unitaires.
Cependant, éliminer la duplication est généralement une bonne chose, tant que cela n'obscurcit rien, et éliminer la duplication dans vos tests peut conduire à une meilleure API. Assurez-vous simplement de ne pas dépasser le point des rendements décroissants.
la source
Le code de mise en œuvre et les tests sont des animaux différents et les règles d'affacturage s'appliquent différemment à eux.
Le code ou la structure dupliquée est toujours une odeur dans le code d'implémentation. Lorsque vous commencez à avoir une mise en œuvre standard, vous devez réviser vos abstractions.
D'autre part, le code de test doit maintenir un niveau de duplication. La duplication dans le code de test atteint deux objectifs:
J'ai tendance à ignorer la duplication triviale dans le code de test tant que chaque méthode de test reste inférieure à environ 20 lignes. J'aime quand le rythme setup-run-verify est apparent dans les méthodes de test.
Lorsque la duplication s'insinue dans la partie "vérifier" des tests, il est souvent avantageux de définir des méthodes d'assertion personnalisées. Bien entendu, ces méthodes doivent encore tester une relation clairement identifiée qui peut être mise en évidence dans le nom de la méthode:
assertPegFitsInHole
-> bon,assertPegIsGood
-> mauvais.Lorsque les méthodes de test deviennent longues et répétitives, je trouve parfois utile de définir des modèles de test à remplir les blancs qui prennent quelques paramètres. Ensuite, les méthodes de test réelles sont réduites à un appel à la méthode modèle avec les paramètres appropriés.
Quant à beaucoup de choses dans la programmation et les tests, il n'y a pas de réponse claire. Vous devez développer un goût et la meilleure façon de le faire est de faire des erreurs.
la source
Je suis d'accord. Le compromis existe mais est différent selon les endroits.
Je suis plus susceptible de refactoriser le code dupliqué pour configurer l'état. Mais moins susceptible de refactoriser la partie du test qui exerce réellement le code. Cela dit, si l'exercice du code prend toujours plusieurs lignes de code, je pourrais penser que c'est une odeur et refactoriser le code réel sous test. Et cela améliorera la lisibilité et la maintenabilité du code et des tests.
la source
Vous pouvez réduire la répétition en utilisant plusieurs types de méthodes de test .
Je suis plus tolérant à la répétition dans le code de test que dans le code de production, mais j'en ai parfois été frustré. Lorsque vous modifiez la conception d'une classe et que vous devez revenir en arrière et modifier 10 méthodes de test différentes qui font toutes les mêmes étapes de configuration, c'est frustrant.
la source
Jay Fields a inventé la phrase que «les DSL doivent être DAMP, pas DRY», où DAMP signifie des phrases descriptives et significatives . Je pense qu'il en va de même pour les tests. De toute évidence, trop de duplication est mauvaise. Mais éliminer à tout prix la duplication est encore pire. Les tests doivent servir de spécifications révélatrices d'intention. Si, par exemple, vous spécifiez la même fonction sous plusieurs angles différents, alors une certaine quantité de duplication est à prévoir.
la source
J'ADORE rspec à cause de ça:
Il a deux choses pour vous aider -
groupes d'exemples partagés pour tester un comportement commun.
vous pouvez définir un ensemble de tests, puis «inclure» cet ensemble dans vos tests réels.
contextes imbriqués.
vous pouvez essentiellement avoir une méthode 'setup' et 'teardown' pour un sous-ensemble spécifique de vos tests, pas seulement pour tous ceux de la classe.
Plus tôt les frameworks de test .NET / Java / autres adopteront ces méthodes, mieux ce sera (ou vous pouvez utiliser IronRuby ou JRuby pour écrire vos tests, ce que je pense personnellement est la meilleure option)
la source
Je pense que le code de test nécessite un niveau d'ingénierie similaire qui serait normalement appliqué au code de production. Il peut certainement y avoir des arguments en faveur de la lisibilité et je conviens que c'est important.
D'après mon expérience, cependant, je trouve que des tests bien pondérés sont plus faciles à lire et à comprendre. S'il y a 5 tests qui se ressemblent chacun à l'exception d'une variable qui a changé et de l'assertion à la fin, il peut être très difficile de trouver ce qu'est cet élément différent. De même, s'il est factorisé de sorte que seule la variable qui change est visible et l'assertion, alors il est facile de comprendre ce que fait le test immédiatement.
Trouver le bon niveau d'abstraction lors des tests peut être difficile et je pense que cela en vaut la peine.
la source
Je ne pense pas qu'il y ait une relation entre un code plus dupliqué et plus lisible. Je pense que votre code de test devrait être aussi bon que votre autre code. Le code non répétitif est plus lisible que le code dupliqué lorsqu'il est bien fait.
la source
Idéalement, les tests unitaires ne devraient pas beaucoup changer une fois qu'ils sont écrits, donc je pencherais vers la lisibilité.
Le fait d'avoir des tests unitaires aussi discrets que possible permet également de garder les tests concentrés sur les fonctionnalités spécifiques qu'ils ciblent.
Cela dit, j'ai tendance à essayer de réutiliser certains morceaux de code que je finis par utiliser encore et encore, comme le code de configuration qui est exactement le même dans un ensemble de tests.
la source
"les a refactorisées pour les rendre plus DRY - l'intention de chaque test n'était plus claire"
Il semble que vous ayez eu du mal à effectuer la refactorisation. Je ne fais que deviner, mais si cela s'avère moins clair, cela ne signifie-t-il pas que vous avez encore plus de travail à faire pour avoir des tests raisonnablement élégants et parfaitement clairs?
C'est pourquoi les tests sont une sous-classe de UnitTest - vous pouvez donc concevoir de bonnes suites de tests qui sont correctes, faciles à valider et à effacer.
Dans les temps anciens, nous avions des outils de test qui utilisaient différents langages de programmation. Il était difficile (voire impossible) de concevoir des tests agréables, faciles à travailler.
Vous avez toute la puissance de - quel que soit le langage que vous utilisez - Python, Java, C # - alors utilisez bien ce langage. Vous pouvez obtenir un bon code de test, clair et pas trop redondant. Il n'y a pas de compromis.
la source