Qualité du code dans les tests unitaires?

23

Lors de l'écriture de tests unitaires, vaut-il la peine de consacrer du temps supplémentaire à rendre le code de bonne qualité et de lisibilité?

Lors de l'écriture de tests, j'enfreins souvent la loi de Demeter , pour une écriture plus rapide et pour éviter d'utiliser autant de variables. Techniquement, les tests unitaires ne sont pas directement réutilisés - ils sont strictement liés au code, donc je ne vois aucune raison de passer beaucoup de temps dessus; ils ont seulement besoin d'être fonctionnels.

m3th0dman
la source
5
La lisibilité et la maintenabilité doivent être au cœur des tests unitaires.
EL Yusubov
2
Les tests sont aussi du code!
Grant Palin
Il fait toujours partie de votre projet, même s'il n'est pas expédié aux clients. Traitez-le en conséquence.

Réponses:

11

Vous devriez certainement prendre le même sinon plus grand soin de vos tests unitaires que votre code de production en termes de qualité et de lisibilité. Les tests unitaires sont souvent la première chose que vous regardez lorsque vous essayez de comprendre ce que fait un morceau de code, et le lecteur doit rapidement comprendre ce qui est en jeu lorsqu'il regarde le test. Les tests unitaires ont également tendance à beaucoup changer et se briseront beaucoup si leur conception n'est pas robuste, ce qui annule les avantages des tests.

La violation de la loi de Demeter est certainement un problème dans vos tests unitaires pour cette raison ainsi que pour 2 autres qui me viennent à l'esprit:

  • Si vos tests enfreignent la loi de Demeter dans leurs sections Arrange ou Act , c'est probablement un signe que votre code de production le fait également, car vos tests unitaires ne sont qu'un autre consommateur de votre code et appellent et opèrent probablement la classe testée de la même manière. façon que tout autre code de production ferait.

  • Si vos tests enfreignent la loi de Demeter dans leurs sections Assert (c'est-à-dire que vous vérifiez la valeur de quelque chose qui est profondément imbriqué dans le graphique des dépendances de l'objet testé), il se peut que ce soient vraiment des tests d'intégration plutôt que des tests unitaires. En d'autres termes, si dans TestA vous affirmez que ABCD est égal à quelque chose, il se peut que vous essayiez en fait de tester D et A plutôt que juste A.

Au fait, quand tu dis

Je casse très souvent la loi de Demeter, pour une écriture plus rapide et ne pas utiliser autant de variables.

vous devez savoir que l'écriture

var grab = myDependency.Grab;
var something = grab.Something;
var very = something.Very;

very.Deep();

est en fait pas mieux Demeter sage que

myDependency.Grab.Something.Very.Deep();

si c'est ce que vous vouliez dire.

guillaume31
la source
47

Cela vaut vraiment la peine de passer du temps à écrire du code de bonne qualité pour les tests unitaires:

  • Ils nécessiteront une maintenance comme tout autre code.
  • Les tests unitaires sont l'une des meilleures sources de documentation pour votre système, et sans doute la forme la plus fiable. Ils devraient vraiment montrer:
    • Intention: "quel est le comportement attendu?".
    • Utilisation: "comment suis-je censé utiliser cette API?".
  • Ils nécessiteront un débogage comme tout autre code.

Le seul facteur en faveur d'une approche légèrement plus ad hoc est que vos tests unitaires ne seront jamais une API publique, vous n'avez donc pas à vous soucier des interfaces / etc. vous exposez.

vaughandroid
la source
22

Oui, c'est important. Il existe plusieurs raisons pour lesquelles les tests unitaires doivent être maintenus à une norme comparable à celle d'un autre code:

  • Chaque test unitaire sert également de documentation au candidat. Lorsque les tests sont complets et couvrent autant de cas marginaux et de conditions d'erreur que possible, ils peuvent souvent remplacer la documentation de commentaire d'une classe ou d'une fonction. Ils peuvent également servir de point de départ pour les nouveaux utilisateurs de la base de code.

  • Les tests unitaires peuvent également être bogués. Et les erreurs sont plus visibles lorsque le code est bien écrit.

  • Si, pour une raison quelconque, vous devez ultérieurement fractionner un module, vous devrez probablement également fractionner ses tests unitaires. C'est plus facile si les tests sont écrits de telle sorte qu'ils ont des dépendances facilement discernables.

Cela dit, il y a toujours la question de l'aspect pratique. Selon la langue et la nature de votre code, il peut être difficile d'écrire des tests unitaires «propres» sans passer beaucoup plus de temps sur les tests que sur le code qu'ils sont censés tester. Dans ce cas, je me retire généralement de tester les choses faciles et rapides et les fonctionnalités les plus critiques, sans trop me soucier de la couverture complète. Chaque fois qu'un bug survient à un stade ultérieur, j'écris un test pour lui et vérifie si je peux refactoriser le nouveau test et les tests existants pour les rendre plus agréables.

Benjamin Kloster
la source
12

si vous ne pouvez pas lire un test unittest et découvrir ce qu'il teste la prochaine fois qu'il échouera, vous passerez le double du temps de débogage (une fois pour savoir de quoi parle le test et une fois pour corriger le code qu'il teste)

honnêtement, les tests devraient avoir un résultat attendu; faire la procédure; obtenir un résultat réel; test attendu par rapport au type réel de structure qui est facile à écrire et à comprendre

monstre à cliquet
la source
1

Le code de test devrait recevoir autant d'amour que votre code de production. Pour plus de lisibilité, peut-être même plus. Si quelqu'un d'autre que vous (y compris vous deux semaines après avoir quitté le code) est censé comprendre ce qui se passe, alors vous devriez rendre votre code agréable et net.

Ça signifie:

  • Extraire la construction des données de test dans des classes de générateur.
  • Extraire des assertions multibles dans des méthodes d'assertion distinctes.
  • Soyez très précis dans votre nom. Assert.That(x4, Is.EqualTo(y16*2*SOME_VALUE), ASS_ERR_TXT_56)fait très peu de sens à la plupart des lecteurs.

Poussés à l'extrême, les tests peuvent être écrits de sorte qu'ils sont presque aussi faciles à lire ET à comprendre que la prose. Le testeur extrême dirait probablement qu'un test unitaire de plus de 10 lignes est mauvais.

Morten
la source
1

La raison pratique la plus importante est que chaque fois que vous changez de code, vous changez les tests unitaires. Et si vous faites du TDD, vous changez même les tests unitaires en premier.

Faites l'une de ces choses dans vos tests:

  • Code en double
  • Diminue la lisibilité
  • Couplage serré
  • Couplage temporel
  • Haute complexité cyclomatique (beaucoup de dépendances)

Et vous avez beaucoup de travail quand un changement est nécessaire.

Traitez vos tests comme vous l'avez suggéré, et vous finirez par le regretter. Vous arriverez probablement même à la fausse conclusion que "TDD ne fonctionne pas".

Yam Marcovic
la source
0

Cela dépend si ces tests unitaires sont "temporaires" ou non. Si

  1. Le test sera fréquemment utilisé;

  2. Les développeurs doivent travailler avec des tests unitaires écrits par d'autres développeurs;

  3. La plupart des tests sont effectués par des tests unitaires

alors les tests doivent être écrits correctement. Dans le cas où il y a un bogue dans le test lui-même, il sera difficile de trouver le bogue et de le corriger, surtout si un certain temps s'est écoulé depuis que le test a été écrit.

D'un autre côté, si ces tests ne sont utilisés que par les développeurs eux-mêmes, alors je pense que c'est ok. Mais il est toujours préférable d'écrire du code «lisible». Comme l'a dit un monstre à cliquet, vous passerez plus de temps à réparer vos tests que vous ne le feriez à les écrire correctement.

superM
la source
(1) les tests unitaires ne sont jamais temporaires (2) même s'ils le sont pour vous-même, dans un mois (ou plus), vous ne vous souviendrez pas de tous les détails, il est donc important de le faire correctement - même pour vous
BЈовић