10
votes

Le rapport "normal" de CodeBase vs tester des problèmes d'affirmation lorsqu'un test échoue?

Je travaille actuellement sur un projet avec des règles commerciales assez importantes où l'espace problématique est «découvert», car nous écrivons la solution (type de gestion de projet chaotique chaotique typique). Nous avons une couverture de test décente et reposez-vous un peu pour vous assurer que nos changements signés ne font rien de quoi que ce soit. Ce scénario est le genre de chose que les zélotes de test unitaire mettent en évidence comme un exemple préférentiel d'aide à l'aide du logiciel d'aide à être facilement modifié avec moins de défauts et d'achèvement plus rapide, puis si vous n'utilisez pas d'essais unitaires. Je frémis de penser à la façon dont je pourrais faire face sans la suite de tests.

Ma question est que, alors que je crois certainement à la valeur des tests unitaires (ce projet est en réalité TDD, mais ce n'est pas vraiment germe à la question), je me demande, d'autres que d'autres, sur le problème de test de l'unité classique d'avoir tellement plus de code à grok et à maintenir (c'est-à-dire les tests eux-mêmes). De nouveau. Il ne fait aucun doute dans mon esprit que ce projet particulier est beaucoup mieux avec le test de l'unité Cruft, alors sans elle , je suis également préoccupé par la maintenabilité à long terme des tests.

Il y a quelques techniques que j'ai utilisées à la suite de l'avis des autres pour aider à ce problème. En général,

  1. Nous créons des listes de test qui sont soit dans un godet inférieur à "indépendant" "dépendant" . Des tests indépendants ne nécessitent rien qui ne soit pas dans le contrôle de la source. Donc, tous les appels vers notre couche d'accès aux données sont moqués ou obtiennent des données à partir d'un fichier XML au lieu du DB réel, par exemple. Les tests dépendants que le nom suggèrent dépendent de quelque chose comme un fichier de configuration ou une db ou une chose Networkie qui pourrait ne pas être correctement configuré / disponible lors de l'exécution du test. Divirant les tests dans des groupes tels que celui-ci a été extrêmement utile en nous permettant d'écrire des tests «Dotir» dépendants pour le développement précoce et des tests critiques indépendants pouvant être invoqués et réinitialisez la pourriture. Il rend également le serveur CI facile à gérer car il ne doit pas nécessairement être configuré et maintenu des connexions W / DB et similaires.
  2. Nous ciblons différents niveaux de notre code . Par exemple, nous avons des tests frappant le «principal» et les tests frappant toutes les méthodes que «principales» appelleraient. Cela nous donne la capacité de cibler les détails du système et des objectifs globaux. Les tests «principaux» sont difficiles à déboguer s'ils se cassent, mais ils ne sont généralement pas la seule chose qui se casse (des tests détaillés cassent également). Il est plus facile de suivre les tests détaillés et de les déboguer si elles se cassent, mais elles sont insuffisantes pour savoir si un refacteur tue le système (c'est ce que les tests «principaux» sont pour).
  3. Les tests «principaux» ont été essentiels pour se sentir à l'aise qu'un refacteur n'a pas reculé du codeBase. Donc, un test «principal» serait comme beaucoup de tests sur une seule méthode appelée différents arguments à utiliser des cas d'utilisation. C'est fondamentalement le point d'entrée dans notre code au plus haut niveau et, en tant que telle, ne sont sans doute pas vraiment des tests «unités». Cependant, je trouve que J'ai vraiment besoin des tests de niveau supérieur afin de vous sentir à l'aise qu'un refacteur n'a pas explosé le codeBase . Les tests de niveau inférieur (ceux qui sont vraiment «unités» du travail) ne sont pas suffisants.

    Tout cela pour aller à la question. Au fur et à mesure que le projet avance et que je trouve que je dois mettre en œuvre des modifications (parfois assez significatives, parfois triviales) au codebase, je trouve que lorsque des modifications entraînent des tests d'échec, Il existe un ratio entre l'échec du test et la logique commerciale régressive réelle Invalidité d'échec et de test unitaire . En d'autres termes, parfois, l'échec du test est dû à un bug de régression dans la base de code actuel et parfois parce que les affirmations de test de l'unité ne sont plus valides et les affirmations doivent être modifiées. Il semble à peu près que lorsque les tests échouent, il s'agit d'environ 50% (50%) pour ce projet particulier.

    Quelqu'un a-t-il suivi ce ratio sur leurs projets et, le cas échéant, quels types de choses avez-vous apprises (le cas échéant) concernant ce ratio? Je ne suis pas sûr que cela indique même quoi que ce soit, mais j'ai remarqué qu'environ la moitié du temps que les défaillances de test me conduisent à ajuster les affirmations de test plutôt que de fixer des bugs de régression dans la vraie basebase. Chaque fois que cela se produit, cela me fait sentir que je viens de perdre x heures de ma journée et je me demande si je pouvais être plus efficace d'une manière ou d'une autre avec mon approche de test. Il faut souvent plus de temps pour résoudre les échecs d'affirmation des tests que les bugs de régression réelles qui sont à la fois contre-adossés et frustrants.

    ÉDITER Notez que cette question consiste à explorer ce que ce ratio signifie et votre expérience avec ce ratio. Quand est-ce que c'est "smelly" ??


1 commentaires

"Notez que cette question consiste à explorer ce que signifie ce ratio". Vous ne devriez pas avoir à dire cela. La question devrait être la question sans explication supplémentaire. Vous pouvez envisager de réécrire la question de se concentrer sur la question. Tout devant "tout cela pour aller à la question" peut être coupé et résumé.


4 Réponses :


4
votes

"Les défaillances de test me conduisent à ajuster les tests d'affirmation plutôt que de fixer des bugs de régression dans le code de code réel."

correct. Vos exigences ont changé. Vos assertions de test doivent changer.

"Cela me fait sentir comme si je viens de perdre x heures de ma journée"

pourquoi? Comment allez-vous les modifications des exigences de la voie?

"Il faut souvent plus de temps pour résoudre les défaillances de test-affirmation que les bugs de régression réelles"

Sans blague. Lorsque vos exigences sont dans un état de flux, cela prend beaucoup de temps et d'efforts pour cartographier les modifications des exigences des changements de résultat de test.

"qui est ... contre-internaute". Dépend de votre intuition. Mon intuition (après 18 mois de TDD) est que les exigences changent conduire à des modifications de conception, de nombreux changements de test complexes pour refléter les modifications de conception.

parfois, très peu (ou non) changements de code.

Si votre code est vraiment bon, cela ne change pas beaucoup. Lorsque vous passez plus de temps à des tests que de code, cela signifie que vous avez écrit un bon code.

rentrer chez vous heureux.

L'odeur de code apparaît lorsque vous dépenserez plus de temps à essayer de faire passer un ensemble de tests qui ne changent jamais. Pensez à ce que cela signifie. Vous avez écrit les tests, mais vous ne pouvez tout simplement pas obtenir de code pour passer. C'est horrible.

Si vous passez une heure à écrire des tests et 4 heures à essayer d'obtenir du code pour réussir les tests, vous avez obtenu un algorithme très complexe (et auriez-vous dû le briser en morceaux plus testables) ou votre application terrible programmeur.

Si vous passez des tests d'écriture d'une heure et 1 heure à obtenir du code, le passage des tests, c'est bon.

Si vous passez des tests de fixation de 2 heures en raison d'une modification des exigences et une heure d'obtention d'un code pour réussir les tests révisés, cela signifie que votre code n'était pas très résilient contre le changement.

Si vous dépensez des tests de fixation de 2 heures en raison d'une modification des exigences et d'un code de peau de 1/2 heure pour réussir ces tests, vous avez écrit un très bon code.


0 commentaires

0
votes

s. Lott beaucoup dit tout. Je pense que la seule chose qu'un rapport d'assertion de test change (t) par rapport aux correctifs de régression (R) vous indiquera que vous combinez la manière dont vos exigences sont volatiles (qui rendront plus plus élevée) par rapport à la réussite du code de l'application en passant à la réussite du code de candidature. test (qui affectera la valeur de r). Ces deux facteurs pourraient varier indépendamment en fonction de la qualité de vos besoins et de vos processus de développement.


0 commentaires

1
votes

Je définitivement la réponse de la deuxième @ S.Lott. Je voudrais simplement souligner que ce qui se passe lorsque la spécification est établie sur des piles d'arbres morts, c'est que lorsque les exigences changent, les arbres morts (ou les fichiers de traitement de texte) ne vous croient pas la façon dont les tests le font, alors tout fonctionne tout simplement Bien, sauf que vous avez cette pile d'arbres morts que tout le monde examine et dit «la documentation est la fiction.»

Cela étant dit, il y a des cas où les tests ne sont tout simplement pas bien écrits ou utiles, et devraient probablement être abandonnés. Je trouve que, surtout avec TDD, où les tests ont taquiné la conception et étaient vraiment incrémentiels, et maintenant que la conception et la fonctionnalité sont plus loin, certains de ces tests originaux ne sont plus pertinents.

Si vous considérez la répartition d'un tas d'essais comme «gaspillé x heures de ma journée», alors lorsque vous passez au deuxième test, vous ne pensez pas à la première après qu'il passe. Cela va faire le coût du changement plus élevé. C'est probablement la bonne décision, mais il n'ya rien de mal à regarder un test et à dire qu'elle a été surmontée par des événements ultérieurs et simplement de le laisser tomber, n'utilisez pas cela aussi bon marché.


0 commentaires

3
votes

J'ai remarqué qu'environ la moitié du temps que les défaillances de test me conduisent à ajuster les affirmations de test plutôt que de fixer des bugs de régression dans la véritable basebase.

Lorsqu'un test échoue, il y a trois options:

  1. La mise en œuvre est cassée et doit être corrigée,
  2. Le test est cassé et doit être fixé, ou
  3. Le test n'est plus nécessaire (en raison de la modification des exigences) et doit être supprimé.

    Il est important d'identifier correctement ce que ce sont les trois options. La façon dont j'écris mes tests, je documentai au nom du test du comportement que le test spécifie / tests, de sorte que lorsque le test échoue, je découvrirai facilement pourquoi le test a été écrit à l'origine. . J'ai écrit plus à ce sujet ici: http: // blog.orfjackal.net/2010/02/three-styles-foNaming-TestS.html

    Dans votre cas,

    • Si vous devez modifier les tests en raison de la modification des exigences et seulement quelques tests à la fois doivent être modifiés, tout est normal (les tests sont bien isolé , de sorte que chaque fonction de comportement soit spécifié par un seul test).
    • Si vous devez modifier les tests en raison de la modification des exigences et de nombreux tests à une heure doivent être modifiés, il s'agit d'un Odeur de test que vous avez beaucoup de tests testant la même chose (les tests sont pas bien isolé). Les tests peuvent être testés Plus d'un comportement intéressant . La solution consiste à écrire des tests plus ciblés et à un meilleur code découplé.
    • Si les tests doivent être modifiés lors du refactoring , il s'agit d'une odeur de test que les tests sont trop étroitement couplés avec des détails de la mise en œuvre. Essayez d'écrire des tests qui sont centrés sur le comportement du système, au lieu de sa mise en œuvre. L'article que j'ai lié précédemment devrait donner vous quelques idées.

      (un point de côté intéressant est que si vous vous trouvez surtout la réécriture de la réécriture , au lieu de les modifier, lorsque les exigences changent, il peut s'agir d'une indication que le code suivait bien SRP, OCP et autres principes de conception.)


0 commentaires