69 votes

Adoption des tests unitaires

Nous avons essayé d'introduire des tests unitaires dans notre projet actuel, mais cela ne semble pas fonctionner. Le code supplémentaire semble être devenu un casse-tête pour la maintenance, car lorsque notre cadre interne change, nous devons faire le tour et corriger tous les tests unitaires qui en dépendent.

Nous avons une classe de base abstraite pour tester l'unité de nos contrôleurs qui agit comme un modèle appelant les implémentations des méthodes abstraites des classes enfants, c'est-à-dire que Framework appelle Initialize, de sorte que nos classes de contrôleurs ont toutes leur propre méthode Initialize.

J'étais auparavant un défenseur des tests unitaires, mais cela ne semble pas fonctionner sur notre projet actuel.

Quelqu'un peut-il m'aider à identifier le problème et me dire comment faire pour que les tests unitaires travaillent pour nous plutôt que contre nous ?

108voto

cwash Points 1683

Conseils :

Éviter d'écrire du code procédural

Les tests peuvent être difficiles à maintenir s'ils sont écrits sur du code de style procédural qui dépend fortement de l'état global ou qui se trouve au cœur du corps d'une méthode laide. Si vous écrivez du code dans un langage OO, utiliser des constructions OO efficacement pour réduire ce phénomène.

  • Évitez l'état global si possible.
  • Évitez les statiques, car elles ont tendance à se propager dans votre base de code et à rendre statiques des éléments qui ne devraient pas l'être. Elles alourdissent également votre contexte de test (voir ci-dessous).
  • Exploiter efficacement le polymorphisme pour éviter trop de si et de drapeaux

Trouvez ce qui change, encapsulez-le et séparez-le de ce qui ne change pas.

Il y a des points d'étranglement dans le code qui changent beaucoup plus fréquemment que d'autres pièces. Faites cela dans votre base de code et vos tests deviendront plus sains.

  • Une bonne encapsulation conduit à de bonnes conceptions à couplage lâche.
  • Refactor et modulariser.
  • Faites en sorte que les tests soient limités et ciblés.

Plus le contexte entourant un test est important, plus il sera difficile de le maintenir.

Faites tout ce que vous pouvez pour réduire les tests et le contexte dans lequel ils sont exécutés.

  • Utilisez le remaniement des méthodes composées pour tester de plus petits morceaux de code.
  • Utilisez-vous un cadre de test plus récent comme TestNG ou JUnit4 ? Ils vous permettent de supprimer la duplication dans les tests en vous fournissant des crochets plus fins dans le cycle de vie des tests.
  • Étudier l'utilisation de doubles de test (mocks, fakes, stubs) pour réduire la taille du contexte de test.
  • Enquêter sur le Créateur de données de test modèle.

Supprimez les doublons dans les tests, mais veillez à ce qu'ils restent ciblés.

Vous ne pourrez probablement pas supprimer tous les doublons, mais essayez tout de même de les supprimer là où ils vous font souffrir. Veillez à ne pas supprimer tellement de doublons que quelqu'un ne puisse pas venir et dire ce que fait le test en un coup d'œil. (Voir l'article de Paul Wheaton "Evil Unit Tests" article pour une explication alternative du même concept).

  • Personne ne voudra réparer un test s'il ne peut pas comprendre ce qu'il fait.
  • Suivez le modèle "arranger, agir, affirmer".
  • N'utilisez qu'une seule assertion par test.

Testez au niveau approprié à ce que vous essayez de vérifier.

Pensez à la complexité impliquée dans un test Selenium d'enregistrement et de relecture et à ce qui pourrait changer sous vous par rapport au test d'une seule méthode.

  • Isoler les dépendances les unes des autres.
  • Utiliser l'injection de dépendance/inversion de contrôle.
  • Utilisez des doubles de test pour initialiser un objet à tester, et assurez-vous de tester des unités de code isolées.
  • Assurez-vous que vous écrivez des tests pertinents
    • "Spring the Trap" en introduisant volontairement un bogue et en veillant à ce qu'il soit détecté par un test.
  • Voir aussi : Les tests d'intégration sont une arnaque

Savoir quand utiliser les tests basés sur l'état et ceux basés sur l'interaction

Les vrais tests unitaires nécessitent une vraie isolation. Les tests unitaires ne touchent pas une base de données ou n'ouvrent pas de sockets. Arrêtez de simuler ces interactions. Vérifiez que vous parlez correctement à vos collaborateurs, et non que le résultat correct de cet appel de méthode est "42".

Démonstration du code de test-driving

On peut débattre de la question de savoir si une équipe donnée adoptera ou non le test-driving de tout le code, ou l'écriture de "tests d'abord" pour chaque ligne de code. Mais devrait-elle écrire au moins quelques tests en premier ? Absolument. Il existe des scénarios dans lesquels les tests d'abord sont sans aucun doute la meilleure façon d'aborder un problème.

Ressources :

19voto

cjk Points 27463

Testez-vous des unités de code suffisamment petites ? Vous ne devriez pas voir trop de changements à moins que vous ne changiez fondamentalement tout dans votre code principal.

Une fois que les choses seront stables, vous apprécierez davantage les tests unitaires, mais même maintenant, vos tests mettent en évidence la mesure dans laquelle les changements apportés à votre cadre sont propagés.

Cela en vaut la peine, tenez bon du mieux que vous le pouvez.

12voto

Mark Simpson Points 10789

Sans plus d'informations, il est difficile de déterminer la raison pour laquelle vous souffrez de ces problèmes. Parfois, il est inévitable que le changement d'interface, etc. casse beaucoup de choses, d'autres fois, c'est dû à des problèmes de conception.

Il est bon d'essayer de catégoriser les échecs que vous constatez. Quel genre de problèmes rencontrez-vous ? Par exemple, s'agit-il de la maintenance des tests (comme les faire compiler après les avoir refactorisés !) due aux changements d'API, ou est-ce dû au changement de comportement de l'API ? Si vous pouvez voir un modèle, alors vous pouvez essayer de changer la conception du code de production, ou mieux isoler les tests des changements.

Si le fait de changer une poignée de choses provoque des ravages incalculables dans votre suite de tests à de nombreux endroits, il y a plusieurs choses que vous pouvez faire (la plupart d'entre elles ne sont que des astuces courantes pour les tests unitaires) :

  • Développer de petites unités de code et les tester de petites unités de code. Extrayez des interfaces ou des classes de base lorsqu'il cela a du sens, de sorte que les unités de code aient des " coutures ". Le plus dépendances que vous devez intégrer (ou pire, instancier à l'intérieur de la classe en utilisant 'new'), plus vous êtes exposé à la votre code sera exposé au changement. Si chaque unité de code a une poignée de dépendances (parfois quelques unes ou pas du tout), elle est mieux isolée du changement.

  • N'affirmez jamais que ce que le test besoin. Ne faites pas d'assertion sur des états intermédiaires, accessoires ou sans rapport. Concevez par contrat et testez par contrat (par ex. si vous testez une méthode de pop de pile, ne testez pas la propriété count après poussée -- cela devrait être dans un test séparé).

    Je vois ce problème assez souvent, surtout si chaque test est une variante. Si l'un de ces l'état accessoire change, cela casse tout ce qui est asserté sur lui (que les assertions soient nécessaires ou pas).

  • Comme pour le code normal, utilisez des fabriques et des constructeurs. dans vos tests unitaires. Je l'ai appris quand une quarantaine de tests avaient besoin d'un appel de constructeur mis à jour après un changement d'API...

  • Tout aussi important, utilisez l'avant porte d'entrée. Vos tests doivent toujours utiliser l'état normal s'il est disponible. N'utilisez les tests basés sur l'interaction que lorsque c'est nécessaire (c'est-à-dire en l'absence d'état à vérifier).

Quoi qu'il en soit, l'essentiel est que j'essaierais de trouver pourquoi/où les tests sont interrompus et de partir de là. Faites de votre mieux pour vous isoler du changement.

8voto

Jon B Points 26872

L'un des avantages des tests unitaires est que, lorsque vous apportez des modifications de ce type, vous pouvez prouver que vous ne brisez pas votre code. Il est vrai que vous devez veiller à ce que vos tests soient synchronisés avec votre framework, mais ce travail plutôt banal est beaucoup plus facile que d'essayer de comprendre ce qui a été cassé lors du remaniement.

4voto

Shell RS Points 625

Je vous conseille de vous en tenir au TDD. Essayez de vérifier votre cadre de test unitaire, faites une RCA (analyse des causes profondes) avec votre équipe et identifiez la zone concernée.

Fixez le code de test unitaire au niveau de la suite et ne modifiez pas fréquemment votre code, en particulier les noms de fonctions ou d'autres modules.

J'apprécierais que vous nous fassiez part de votre étude de cas, afin que nous puissions mieux cerner le problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X