Quelle est la valeur de la vérification des tests unitaires ayant échoué?

13

Bien qu'il existe des moyens d'empêcher l'exécution des tests unitaires, quelle est la valeur de la vérification des tests unitaires ayant échoué?

J'utiliserai un exemple simple: la sensibilité à la casse. Le code actuel est sensible à la casse. Une entrée valide dans la méthode est "Cat" et elle renverrait une énumération de Animal.Cat. Cependant, la fonctionnalité souhaitée de la méthode ne doit pas être sensible à la casse. Donc, si la méthode décrite était passée "cat", elle pourrait éventuellement renvoyer quelque chose comme Animal.Null au lieu d'Animal.Cat et le test unitaire échouerait. Bien qu'un simple changement de code rendrait cela possible, un problème plus complexe peut prendre des semaines à résoudre, mais l'identification du bogue avec un test unitaire pourrait être une tâche moins complexe.

L'application en cours d'analyse dispose de 4 ans de code qui "fonctionne". Cependant, des discussions récentes concernant les tests unitaires ont trouvé des failles dans le code. Certains ont juste besoin d'une documentation d'implémentation explicite (ex. Sensible à la casse ou non), ou d'un code qui n'exécute pas le bogue en fonction de la façon dont il est actuellement appelé. Mais des tests unitaires peuvent être créés en exécutant des scénarios spécifiques qui feront que le bogue sera vu et seront des entrées valides.

Quelle est la valeur de l'archivage des tests unitaires qui exercent le bogue jusqu'à ce que quelqu'un puisse résoudre le code?

Ce test unitaire doit-il être marqué avec ignorer, priorité, catégorie, etc., pour déterminer si une construction a réussi en fonction des tests exécutés? Finalement, le test unitaire doit être créé pour exécuter le code une fois que quelqu'un le corrige.

D'une part, cela montre que les bogues identifiés n'ont pas été corrigés. De l'autre, il pourrait y avoir des centaines de tests unitaires ayant échoué apparaissant dans les journaux et éliminant ceux qui devraient échouer par rapport aux échecs dus à un enregistrement de code serait difficile à trouver.

Jim G.
la source
C'est une façon d'augmenter ces chiffres de couverture de test.
JeffO
Si vous avez déjà fait l'effort d'écrire le test unitaire, pourquoi voudriez-vous avoir à le réécrire lorsque vous décidez de résoudre le problème? Ce n'est pas parce qu'il est archivé qu'il doit être exécuté dans la suite. (Vous pouvez créer une catégorie pour "Problèmes connus" et traiter ces tests comme une liste de backlog / TODO.)
Caleb

Réponses:

17

Je n'aime pas les unités cassées enregistrées car elles produisent un bruit inutile. Après chaque test, je devrais vérifier tous les problèmes ayant échoué (rouge). Est-il rouge parce qu'il y a un nouveau problème ou parce qu'il y a un ancien ouvert à faire / à corriger. Ce n'est pas correct s'il y a plus de 20 unités.

J'utilise plutôt

  • [Ignore("Reason")]attribut qui rend le résultat jaune ou
  • throw new NotImplementedException()qui rend le résultat gris

Remarque: j'utilise NUnit pour .net. Je ne sais pas si la fonction "grise" est là dans d'autres frameworks les plus instables.

J'aime donc la signification suivante des résultats des tests unitaires.

  • vert: tout est fini
  • gris: nouvelles fonctionnalités prévues qui doivent être effectuées mais avec une faible priorité
  • jaune: les bugs ne sont pas encore corrigés. Devrait être corrigé bientôt
  • rouge: nouveaux bugs. Doit être corrigé immédiatement

Tout sauf "rouge" peut être enregistré.

Pour répondre à la question: il y a plus de mal que de valeur à archiver "test-échoué rouge" mais archiver "test ignoré-jaune" ou "test non-gris" peut être utile comme liste de tâches.

k3b
la source
le problème que je vois avec cette approche est que les tests ignorés ne seront probablement jamais corrigés. Vous pouvez également supprimer tout le code de test, quelle serait la différence (je suis un peu arrogant ici)
Lovis
4
will probably never be fixedest une décision politique si vous voulez vous dépenser dans des tests automatisés ou non. Avec les "tests ignorés", vous avez la possibilité de les corriger. Jeter les «tests ignorés» signifie «abandonner les tests automatisés peu à peu jusqu'à ce qu'il n'y en ait plus»
k3b
8

Je ne prétendrai pas que c'est la norme de l'industrie, mais j'archive les tests cassés pour me rappeler, à moi ou à mes autres membres du projet, qu'il y a toujours un problème avec le code ou le test unitaire lui-même.

Je suppose qu'une chose à considérer est de savoir si vos politiques de développement permettent d'échouer les tests sans pénalité. J'ai un ami qui travaille dans un magasin qui fait du développement piloté par les tests, donc il commence toujours par des tests qui échouent ...

Tieson T.
la source
5
Mais vous ne devez jamais archiver un test ayant échoué, car votre serveur de build ne doit pas construire un projet avec un test cassé.
CaffGeek
@Chad: La construction et les tests sont deux parties distinctes d'une seule étape automatisée. La construction garantit que tout se compile. Le test garantit que le résultat de la génération est valide. Mon interprétation de la question n'était pas, "dois-je archiver du code qui ne compile pas?" Au lieu de cela, c'était: "devrais-je enregistrer un test dont je sais qu'il échouera?"
unholysampler
1
J'ajoutais juste un point à considérer, certains serveurs de build d'intégration continue exécutent les tests et s'ils échouent, ils ne sont pas déployés. À juste titre, comme si la construction échoue, le code échoue et il est inutile de déployer un produit connu pour être cassé.
CaffGeek
@Chad: Oui, j'ai totalement oublié les serveurs CI. Ce serait certainement un point à considérer. Il vaut également la peine de clarifier ce que nous entendons par tests «cassés»; S'agit-il simplement de «mauvais» tests ou le test échoue-t-il parce que l'API a changé d'une manière ou d'une autre?
Tieson T.
La question aurait dû être plus claire. Ce devrait être le test qui sera compilé, mais le résultat attendu échouera.
6

L'échec des tests unitaires donne à l'équipe de développement une visibilité sur ce qui doit être fait pour se conformer aux spécifications convenues.

En bref, l'échec des tests unitaires donne à l'équipe une liste de "TODO".

Pour cette raison, l'échec des tests unitaires est bien meilleur que l'absence de tests unitaires. *
L'absence de tests unitaires laisse l'équipe de développement dans le noir; les spécifications doivent être confirmées manuellement à plusieurs reprises .

[* À condition que les tests unitaires testent réellement quelque chose d'utile.]

Jim G.
la source
2
Il existe de meilleures façons de gérer une liste de tâches, par exemple un tableau blanc, une application de liste de tâches ou un système de suivi des problèmes. Il est beaucoup plus facile d'utiliser une suite de tests si vous vous attendez à ce qu'elle passe toujours pleinement, et tout échec de test qui apparaît est alors un nouveau problème à résoudre immédiatement.
bdsl
6

Le but des tests unitaires est d'affirmer le comportement attendu d'un système, et non de documenter les défauts. Si nous utilisons des tests unitaires pour documenter les défauts, leur utilité pour affirmer le comportement attendu s'en trouve diminuée. La réponse à la question "Pourquoi ce test a-t-il échoué?" n'est pas un simple "Oh, quelque chose est cassé que je ne m'attendais pas à être cassé." On ne sait pas si l'échec du test est prévu ou inattendu.

Voici un paragraphe du début du chapitre 13 de Travailler efficacement avec le code hérité :

Les tests unitaires automatisés sont un outil très important, mais pas pour la recherche de bogues - pas directement, du moins. En général, les tests automatisés doivent spécifier un objectif que nous aimerions atteindre ou tenter de conserver un comportement qui existe déjà. Dans le flux naturel du développement, les tests qui précisent deviennent des tests qui préservent . Vous trouverez des bogues, mais généralement pas la première fois qu'un test est exécuté. Vous trouvez des bogues dans des exécutions ultérieures lorsque vous modifiez un comportement auquel vous ne vous attendiez pas.

Matthew Rodatus
la source
3

Mais les cassés qui identifient les bugs dans un nouveau projet, nommé comme tel. De cette façon, vous pouvez voir qu'ils DEVRAIENT casser ... Pendant qu'ils sont corrigés, ils deviendraient verts et seraient déplacés dans la suite de tests normale.

REMARQUE: ce projet devrait être défini pour ne pas être généré sur le serveur de génération, si votre serveur de génération empêche les archivages qui interrompent la génération (en supposant que vous définissez une génération rompue comme une génération dans laquelle tous les tests ne passent pas)

CaffGeek
la source
+1 bien qu'il n'y ait pas de réponse pour vérifier ou non il y a un argument important: construire un serveur
k3b
Je préfère utiliser un attribut pour marquer un tel test au lieu de le déplacer vers un projet distinct.
CodesInChaos
2

Les tests unitaires doivent tester les cas d'erreur en plus des cas de réussite d'une fonction. Une fonction doit explicitement rejeter une entrée incorrecte ou doit avoir une documentation pour expliquer quelle entrée est considérée comme valide.

Si vous avez une fonction qui ne fait aucune de ces choses, c'est un bug et vous devriez avoir un moyen d'enregistrer qu'elle existe. La création d'un test unitaire qui illustre ce problème est une façon de le faire. Le dépôt d'un ticket de bug est une autre option.

Le point de test unitaire n'est pas d'avoir 100% de succès, il s'agit de trouver et de corriger les bugs dans le code. Ne pas faire de tests est un moyen facile d'avoir 100% de succès, mais ce n'est pas très bénéfique pour le projet.

unholysampler
la source
Woah ... "Le but des tests unitaires n'est pas d'avoir 100% de succès", dites-vous qu'ils n'ont pas tous besoin de passer!?
CaffGeek
2
@Chad: Le fait est qu'il vaut mieux avoir des tests dont vous savez qu'ils échoueront, mais qui démontrent un vrai problème au lieu de ne pas avoir le test juste pour que vous puissiez avoir la coche verte à la fin de la construction / test nocturne.
unholysampler
8
@unholysampler, ne jamais avoir de tests cassés, sauf s'ils sont clairement marqués comme "devrait" se casser (en étant dans un projet différent). Sinon, ils deviennent du bruit et vous ne savez pas quand un test qui devrait être réussi a été cassé. Il va complètement à l'encontre du but de l'intégration continue et des tests unitaires
CaffGeek
2
@Chad: Je pense que cela entre dans la sémantique des définitions. Sur la base de l'OP, il semblait qu'il parlait de créer un test valide qui exerce un bug. Cependant, le bogue est de faible priorité et ne devrait pas être corrigé immédiatement. Vous êtes celui qui a introduit l'intégration continue, qui impose des restrictions beaucoup plus strictes au processus automatisé.
unholysampler
4
@unholysampler, CI ou pas de CI, le fait est que lorsque vous exécutez les tests et que vous avez l'habitude de voir des voyants rouges, vous vous y habituez. Alors, quand quelque chose qui était vert devient rouge ... comment savez-vous?!? C'est une pratique horrible, et l'une des raisons pour lesquelles les tests ne sont pas acceptés dans de nombreuses organisations.
CaffGeek
1

Enregistrez un bogue pour chaque échec et notez-le dans le résultat du test. Ensuite, si jamais vous vous réunissez et corrigez le bug, votre test réussit et vous le supprimez du résultat du test. N'ignorez jamais les problèmes.

SnoopDougieDoug
la source
-3

Comment je vois TDD fait avec l'implémentation de tests pour un code inachevé est, écrivez d'abord les tests avec l'attribut [ExpectedException] ou similaire. Cela devrait passer initialement car le code incomplet ne contiendrait aucune logique et y écrire un nouveau code Exception (). Bien que l'exception soit erronée, cela ferait au moins réussir les tests initialement et conviendrait à l'enregistrement. Nous pouvons oublier un test ignoré, mais nous pouvons certainement ranger ou remplir le code incomplet. Lorsque nous le faisons, automatiquement le test correspondant qui s'attendait à une excpetion commencerait maintenant à échouer et vous alarmerait pour le corriger. Cela peut impliquer une légère modification du test pour se débarrasser de ExpectException et faire de véritables assertions. CI, Dev, testeurs et clients tous heureux et une situation gagnant-gagnant?

user211764
la source
1
Cela ne répond pas à la question. Il ne demande pas ce qu'est TDD et pourquoi tester les exceptions attendues.
Andy Wiesendanger