Question

J'ai perdu plusieurs tests unitaires, il y a quelque temps, lorsque je les ai réorganisés pour les rendre plus DRY. - l'intention de chaque test n'était plus claire. Il semble y avoir un compromis entre la lisibilité et la maintenabilité des tests. Si je laisse du code en double dans les tests unitaires, ils sont plus lisibles, mais si je change de SUT , Je vais devoir rechercher et modifier chaque copie du code dupliqué.

Convenez-vous que ce compromis existe? Si oui, préférez-vous que vos tests soient lisibles ou maintenables?

Était-ce utile?

La solution

Le code dupliqué est une odeur dans le code de test unitaire, tout autant que dans les autres codes. Si vous avez dupliqué du code dans les tests, il devient plus difficile de refactoriser le code d'implémentation car vous avez un nombre de tests disproportionné à mettre à jour. Les tests devraient vous aider à refactoriser vos données en toute confiance, plutôt que d’être une lourde charge pour votre travail sur le code testé.

Si la duplication est en cours d'installation, envisagez d'utiliser davantage la méthode setUp ou de fournir plus (ou plus flexible) Méthodes de création .

Si la duplication se trouve dans le code manipulant le SUT, demandez-vous pourquoi plusieurs "unités" dites "# 8220; unités" & # 8221; les tests exercent exactement la même fonctionnalité.

Si la duplication se trouve dans les assertions, vous avez peut-être besoin de Assertions personnalisées . Par exemple, si plusieurs tests comportent une chaîne d'assertions telle que:

assertEqual('Joe', person.getFirstName())
assertEqual('Bloggs', person.getLastName())
assertEqual(23, person.getAge())

Dans ce cas, vous avez peut-être besoin d'une seule méthode assertPersonEqual pour pouvoir écrire assertPersonEqual (Person ('Joe', 'Bloggs', 23), personne) . (Ou peut-être devez-vous simplement surcharger l'opérateur d'égalité sur Personne .)

Comme vous l'avez dit, 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 le refactoring pour supprimer la duplication aide à la lisibilité, car chaque ligne de chaque méthode de test est directement pertinente pour 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 passe-partout.

Cela étant dit, il arrive que des tests exercent des situations complexes similaires, mais néanmoins significativement différentes, et il est difficile de trouver un moyen efficace de réduire les doubles emplois. Faites preuve de bon sens: si vous estimez que les tests sont lisibles et explicites, et que vous devez peut-être mettre à jour plus qu'un nombre théoriquement minimal de tests lors de la refactorisation du code invoqué par les tests, acceptez alors l'imperfection et déplacez sur quelque chose de plus productif. Vous pouvez toujours revenir plus tard et refactoriser les tests, lorsque l'inspiration vous sourira!

Autres conseils

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 pondéré 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 unitaires.

Cependant, éliminer la duplication est généralement une bonne chose, à condition que cela ne cache rien, et éliminer la duplication dans vos tests peut conduire à une meilleure API. Assurez-vous simplement de ne pas dépasser le seuil des rendements décroissants.

Le code de mise en œuvre et les tests sont des animaux différents et les règles de factoring leur sont appliquées différemment.

Le code ou la structure dupliqué est toujours une odeur dans le code d'implémentation. Lorsque vous commencez à avoir une phase d'exécution dans la mise en œuvre, vous devez réviser vos abstractions.

D'autre part, le code de test doit conserver un niveau de duplication. La duplication dans le code de test permet d'atteindre deux objectifs:

  • Conserver les tests découplés. Un couplage de test excessif peut rendre difficile la modification d’un test ayant échoué qui doit être mis à jour car le contrat a été modifié.
  • Conservez les tests significatifs de manière isolée. Lorsqu'un seul test échoue, il doit être relativement simple de savoir exactement ce qu'il teste.

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 se faufile dans le champ "vérifier". Dans le cadre des tests, il est souvent utile de définir des méthodes d’assertion personnalisées. Bien entendu, ces méthodes doivent toujours tester une relation clairement identifiée qui peut être mise en évidence dans le nom de la méthode: assertPegFitsInHole - > bien, assertPegIsGood - > mauvais.

Lorsque les méthodes de test deviennent longues et répétitives, il est parfois utile de définir des modèles de test à remplir en blanc qui prennent quelques paramètres. Ensuite, les méthodes de test réelles sont réduites à un appel à la méthode de modèle avec les paramètres appropriés.

Pour ce qui est de la programmation et des tests, il n’ya 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.

Vous pouvez réduire le nombre de répétitions en utilisant plusieurs types de méthodes utilitaires de test .

Je suis plus tolérant vis-à-vis de la répétition dans le code de test que dans le code de production, mais cela m'a parfois frustré. Lorsque vous modifiez la conception d'une classe et que vous devez modifier 10 méthodes de test différentes qui effectuent toutes les mêmes étapes d'installation, c'est frustrant.

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 susceptibles 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 un refactor du code réel à tester. Et cela améliorera la lisibilité et la maintenabilité du code et des tests.

Jay Fields a forgé l’expression "DSL doit être DAMP et non DRY", où DAMP signifie des phrases descriptives et significatives . Je pense que la même chose s'applique aux tests, aussi. De toute évidence, trop de duplication est mauvaise. Mais éliminer la duplication à tout prix est encore pire. Les tests doivent agir en tant que spécifications révélant l'intention. Si, par exemple, vous spécifiez la même fonctionnalité sous plusieurs angles différents, il faut s'attendre à une certaine duplication.

J'adore rspec pour cette raison:

Il a 2 choses à aider -

  • exemples de groupes partagés pour tester le comportement commun.
    vous pouvez définir un ensemble de tests, puis "inclure" cet ensemble dans vos vrais tests.

  • contextes imbriqués.
    vous pouvez avoir essentiellement une méthode de "configuration" et de "démontage" pour un sous-ensemble spécifique de vos tests, pas seulement pour ceux de la classe.

Plus tôt les frameworks de test .NET / Java / autres adopteront ces méthodes, mieux ce sera (ou vous pourriez utiliser IronRuby ou JRuby pour écrire vos tests, ce qui, à mon avis, est la meilleure option)

Je ne pense pas qu'il y ait une relation entre davantage de code dupliqué et 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 exécuté.

Idéalement, les tests unitaires ne devraient pas beaucoup changer une fois qu'ils ont été écrits, je me suis donc tourné vers la lisibilité.

Le fait que les tests unitaires soient aussi discrets que possible contribue également à maintenir les tests centrés sur les fonctionnalités spécifiques qu'ils ciblent.

Cela dit, j’ai tendance à essayer de réutiliser certains éléments de code que je finis par utiliser encore et encore, tels que le code de configuration qui est exactement identique à l’ensemble des tests.

Je pense que le code de test nécessite un niveau d'ingénierie similaire à celui 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, j'estime que les tests bien pondérés sont plus faciles à lire et à comprendre. S'il y a 5 tests qui se ressemblent, à l'exception d'une variable qui a été modifiée et de l'assertion à la fin, il peut être très difficile de déterminer le type de cet élément différent. De même, si elle est factorisée de sorte que seule la variable en train de changer soit visible et l'assertion, alors il est facile de comprendre ce que le test fait immédiatement.

Il peut être difficile de trouver le niveau d'abstraction approprié lors des tests et j'estime que cela en vaut la peine.

"Ils ont été remaniés pour les rendre plus secs. L'intention de chaque test n'était plus claire"

On dirait que vous avez eu du mal à refactoriser. Je ne fais que deviner, mais si tout se passe bien, cela ne signifie-t-il pas qu'il vous reste encore du travail à faire pour disposer de tests raisonnablement élégants et parfaitement clairs?

C'est pourquoi les tests sont une sous-classe de UnitTest. Vous pouvez ainsi concevoir de bonnes suites de tests correctes, faciles à valider et à effacer.

Autrefois, nous avions des outils de test utilisant différents langages de programmation. Il était difficile (ou impossible) de concevoir des tests agréables et faciles à utiliser.

Vous avez toute la puissance - quel que soit le langage que vous utilisez - Python, Java, C # - utilisez donc bien ce langage. Vous pouvez obtenir un code de test esthétique, clair et pas trop redondant. Il n'y a pas de compromis.

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