IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Les Mocks détériorent-ils les tests unitaires ?
Selon un développeur, le testing se portait mieux avant

Le , par Amine Horseman

115PARTAGES

4  2 
Tomasz Wegrzanowski, développeur logiciel à Londres, a publié récemment un billet de blog critiquant la dégradation de la qualité des tests unitaires.

« Il était une fois, avant que le testing soit devenu généralisé, je croyais que les tests unitaires amélioraient considérablement la qualité des logiciels » déclare-t-il, « il était extrêmement évident combien était horrible le code qui ne possédait pas de tests unitaires, et le code qui en avait était généralement beaucoup plus organisé. Quelques années plus tard, une fois que les tests ont commencé à devenir la nouvelle orthodoxie, je commençais à remarquer quelque chose de nouveau : du code raisonnablement couvert par des tests unitaires, mais qui était de l’intérieur un désordre total ».

Le problème selon lui est que les tests automatisés protègent le code des bugs selon le modèle du 80:20. En d’autres termes : 20% des tests permettent de capturer 80% des problèmes, ce qui implique que 80% des tests ne capturent que les 20% des bugs restants. Ceci pousse donc Wegrzanowski à considérer les tests uniquement pour les parties de base du code, ce qui permet selon lui de couvrir « la majorité des cas courants » avec « seulement une fraction de temps pour écrire et maintenir les tests ».

Un autre problème selon lui -hormis le fait que les tests unitaires ne permettent pas de découvrir les bugs graves tels que les failles de sécurité- c’est qu’ils ne permettent pas de tester un composant individuel s’il ne peut pas être isolé de l’ensemble du système. Ceci obligeait donc les programmeurs à réécrire leurs codes d’une façon « démêlée » ce qui améliorerait grandement la qualité du code selon Tomasz Wegrzanowski, jusqu’à ce que « quelqu’un inventa le Mocking et fasse tout casser ».

Selon lui, les Mocks ne « testent pas grand-chose et donnent une fausse confiance ». Ces objets simulés qui reproduisent le comportement d'objets réels ne peuvent pas faire de mal s’ils sont utilisés avec réserve déclare l’auteur du billet, mais cela nécessite « beaucoup de discipline » selon lui puisqu’on est tenté de se dire « bon, je pourrais tester ceci correctement, mais le Mocking est plus facile, je vais donc juste écrire quelques faux tests sous pression ».

Pour Wegrzanowski les Mocks souffrent du même problème que le C ++ : « quasiment chaque fonctionnalité ajoutée était là pour une raison. Mais ça n'a pas d'importance, car le résultat final de l’ajout le toutes ces fonctionnalités sans distinction était un désastre total ».

Source : TAW’s Blog

Et vous ?

Êtes-vous d’accord avec l’avis de Tomasz Wegrzanowski ?
Que pensez-vous de l’utilisation des Mocks dans les tests unitaires ?

Une erreur dans cette actualité ? Signalez-nous-la !

Avatar de Bono_BX
Membre confirmé https://www.developpez.com
Le 06/05/2015 à 9:50
Mouais ... j'ai comme l'impression que nous avons encore un gars qui ne sait pas de quoi il parle, d'un programmeur qui s'est à moitié renseigné sur le sujet ...

20% des tests permettent de capturer 80% des problèmes, ce qui implique que 80% des tests ne capturent que les 20% des bugs restants.
Et le concept de non-régression, il a déjà entendu parler ? Les tests unitaires ne servent pas qu'à détecter les bugs, ils servent aussi à les en empêcher. De plus, et là l'expérience avec les mocks est très utile, ils servent aussi à architecturer correctement le code (quand on fait du TDD, bien entendu).

les Mocks ne « testent pas grand-chose et donnent une fausse confiance »
Merci Captain Obvious ! Ce n'est juste pas leur but ... les mocks se substituent à des objets, mais ne testent strictement rien.

puisqu’on est tenté de se dire « bon, je pourrais tester ceci correctement, mais le Mocking est plus facile, je vais donc juste écrire quelques faux tests sous pression »
Rien à voir avec le mocking, la problématique est la compétence du programmeur. C'est exactement la même chose que le copier-coller de code vs la factorisation. Bref, il est complètement hors sujet.

Pour rappel, il y a trois grands types de tests (les dénominations changent selon les personnes, mais les principes sont les mêmes) :
  • les tests unitaires, qui ne testent qu'une seule fonction. On utilise donc les mocks pour l'isoler des autres fonctions et de l'environnement (au sens large).
  • Les test d'intégration (ATTENTION : ce nom est souvent employé pour d'autres tests), qui sont souvent assimilés aux tests unitaires. Ces tests n'utilisent de préférence pas les mocks, permettant à une fonction d'effectuer "en réel" tous ses appels, et interagit avec l'environnement. Plus coûteux, ils n'en sont pas moins intéressant car en plus de tester les fonctions "en vrai", ils s'avèrent précieux pour tout ce qui est problématiques de performances et de montée en charge (ceci n'est qu'un exemple).
  • Les tests d'interface : un automate simule les actions des utilisateurs et vérifie que les retours de l'application (UI, BDD, fichiers ...) sont corrects.


L'idéal est bien évidemment d'avoir ces trois types de tests ; mais là, c'est bien souvent une utopie, car le cout devient important (bien que justifié).

Pour Wegrzanowski les Mocks souffrent du même problème que le C ++ : « quasiment chaque fonctionnalité ajoutée était là pour une raison. Mais ça n'a pas d'importance, car le résultat final de l’ajout le toutes ces fonctionnalités sans distinction était un désastre total ».
Le C++, un désastre total ???? !!!!!!!!
7  0 
Avatar de Ithildine
Membre régulier https://www.developpez.com
Le 06/05/2015 à 9:12
Cela fait quelques temps que j'utilise Mockito et Powermock. Ces outils sont très précieux pour isoler une classe de ses dépendances, d'une part, et aussi pour tester son comportement dans des situations presque impossibles à reproduire autrement. Un exemple de cela est la levée d'une exception de type précis au cinquième appel de méthode sur une dépendance. Bref, les objets simulés (parlons français, s'il vous plait ;-) ) sont un gros plus à mon sens.
Toutefois, ils ne sont que des outils et ne dispensent pas de garder un oeil vigilant sur le code qu'ils testent. D'ailleurs, je trouve même qu'ils sont également un outil très intéressant pour évaluer la qualité de ce code et nous remonter sur celui-ci pas mal de signes qu'il convient d'apprendre à interpréter:
- Si le nombre d'objets mocks pour tester est trop important, c'est bien évidement que la classe initiale dépend de trop de choses et est donc trop fragile. Il convient donc de la découper en plusieurs autres classes et donc de repenser son contrat fonctionnel initial.
- Si les règles de comportement des objets simulés deviennent trop compliquées, c'est aussi le signe que la classe testée à un problème, et très souvent elle fait également trop de choses et son contrat fonctionnel doit là encore être revu et découpé. Parfois, simplement déléguer à une nouvelle classe une partie de l'implémentation technique de la classe testée restaure la lumière et permet une nouvelle batterie de tests bien plus simples sur cette nouvelle classe alors que le test qui posait problème devient lui aussi bien plus simple, des dépendances se trouvent aussi déplacées dans la classe déléguée, ce qui permet souvent aussi même de supprimer certains tests de la classe initiale.

Mon opinion sur les objets simulés n'est pas figée et changera sans doute encore à mesure que j'assimile certaines de leurs utilisations possibles. Ces objets sont un outil très puissant mais comme tous les outils puissants, il convient de ne pas généraliser aveuglement leur utilisation mais de les employer de manière très ciblée et en restant très vigilants sur ce qu'ils font transparaitre du code testé (trop de responsabilité, contrat fonctionnel peu clair ou multiple, trop complexe, trop de dépendances). Chaque fois qu'un sentiment désagréable se manifestait dans mon utilisation de ces objets simulés, c'était presque invariablement le signe d'un problème de conception dans la classe initiale, il faut apprendre à interpréter cela et ce n'est pas facile.

EDIT : généralement, je ne dégaine pas d'amblée Mockito. J'essaie toujours de faire une simple test JUnit, quitte même parfois à améliorer un peu le code de ma classe. Je ne passe en test Mockito que quand toutes les autres solutions qui me viennent à l'esprit sont plus complexes ou moins lisibles.
3  0 
Avatar de Laurent 1973
Membre chevronné https://www.developpez.com
Le 06/05/2015 à 11:50
Heu, dans cette article, j'ai l'impression de ne plus comprendre la définition de Mock.

Pour moi, une classe Mock est une classe de bouchonnage, programmable pour qu'elle simule un comportement, que l'on utilise dans un test unitaire en isolation pour s'extraire des couches plus basse.

J'ai l'impression que l'on fait un amalgame avec certain framework de test en java qui en plus de bouchonner une couche, exécute en automatique certain tests sans quasiment aucune programmation.
Est-ce que je me trompe?

Si c'est bien ça que j'ai compris, je serais alors d'accord avec l'auteur.
L'écriture de tests nécessitent du temps et un coup.
Et de dire: "j'ai testé ce module" juste parce qu'un framework balance en automatique des valeurs sur un large panel et qu'il vérifie que cela ne plante pas, et en effet une simplification dangereuse.

J'ai tendance à réaliser mes tests en TDD via de simple xUnit en réalisant moi-même mes classe de bouchonnage
Je jumelle cela à une analyse de couverture de code sur mon intégration continue.
Cela révèle en premier jet qu'en effet 20-30% du code n'est pas couvert correctement.
Je m’intéresse alors aux branches conditionnelles non couverte (et pas ligne par ligne) comme l'évoque tanatiel

Sur un des dernier petit projet que j'ai réalisé ainsi en Python, je tournais vers 91 % de couverture de tests sur 10000 lignes.
Et encore, les lignes non couvertes correspondaient souvent sur des gestions d'erreurs exotiques (erreurs d'écriture sur disque, problème réseau, ...) que l'on pouvait tester facilement qu'en manuel.

C'est sur qu'en Python, on a pas le compilateur qui va pouvoir vous signaler certains bugs potentiel.
Une forte couverture de code sur les testes est capital si vous ne voulez pas que cela explose pour un simple "fonction trucmuche inconnue!"
2  0 
Avatar de tanatiel
Membre régulier https://www.developpez.com
Le 06/05/2015 à 9:23
Pour avoir découvert JMock lors de mon dernier projet, j'aurai tendance à dire qu'il faut surtout bien comprendre le fonctionnement de ce genre d'outil et une fois maîtrisé, il permet de faire des choses intéressantes comme par exemple vérifier le nombre d'appels à un Mock et ainsi confirmer l'adhérence entre les différents objets / services.

A mon sens, il est surtout idiot de faire du test unitaire pour couvrir des lignes, ça n'a pas beaucoup d'intérêt. Il me parait plus intéressant de couvrir les branches car c'est souvent dans les branches non couvertes que se glissent les régressions, d'après mon expérience.
1  0 
Avatar de mermich
Membre expérimenté https://www.developpez.com
Le 06/05/2015 à 19:38
Moi j'ai beaucoup ris:
20% des tests permettent de capturer 80% des problèmes, ce qui implique que 80% des tests ne capturent que les 20% des bugs restants

Du coup selon lui les tests capturent 100% des bugs ?

Si lui arrive a le faire et qu'il me le garantie, je l'embauche direct !
1  0 
Avatar de heid
Membre confirmé https://www.developpez.com
Le 06/05/2015 à 10:50
Perso j'utilise des mock dans les tests unitaires pour assurer une simplicité et rapidité d'execution et des instances réelles dans les tests d'intégration lancés une fois par jour.

J'ai jamais eu le moindre problème d'un mock qui m'a fait rater un bug.

Je parle d'un projet avec 2000 tu et 60% de couverture.
0  0 
Avatar de Bono_BX
Membre confirmé https://www.developpez.com
Le 06/05/2015 à 13:03
Pour moi, une classe Mock est une classe de bouchonnage, programmable pour qu'elle simule un comportement, que l'on utilise dans un test unitaire en isolation pour s'extraire des couches plus basse
Tu as tout à fait raison. C'est bien l'auteur de l'article qui laisse entendre une définition erronée des mocks.
0  0 
Avatar de CodeurPlusPlus
En attente de confirmation mail https://www.developpez.com
Le 07/05/2015 à 3:59
Purée mais c'est que je ne comprends plus rien au vocabulaire de l'informaticien moderne...
0  0 
Avatar de Logan Mauzaize
Rédacteur/Modérateur https://www.developpez.com
Le 11/05/2015 à 15:53
La lecture mineutieuse de la source permet de mieux rendre compte de l'idée de l'auteur :
  • TDD est là pour influencer (de manière positive) la mise en place de l'architecture. En effet, le code des tests nous forcent à refactorer pour "simplifier" les choses et donc les rendre plus propre. Cependant, en "simulant" des comportements, on se prémunit de gérer la complexité du système et le besoin de refactoring (et donc d'amélioration de l'architecture) tend à être moins important.
  • La comparaison avec le C++ tient au faîte que l'outil est relativement puissant et très permissif dans son utilisation. Et donc chaque idée prise séparémment donc très bonnes mais leurs utilisations donnent souvent des résultats monstreux (au sens négatif du terme).


Quelques précisions par rapport aux interventions précédentes :

Citation Envoyé par Bono_BX Voir le message
Pour rappel, il y a trois grands types de tests (les dénominations changent selon les personnes, mais les principes sont les mêmes) :
  • les tests unitaires, qui ne testent qu'une seule fonction. On utilise donc les mocks pour l'isoler des autres fonctions et de l'environnement (au sens large).
  • Les test d'intégration (ATTENTION : ce nom est souvent employé pour d'autres tests), qui sont souvent assimilés aux tests unitaires. Ces tests n'utilisent de préférence pas les mocks, permettant à une fonction d'effectuer "en réel" tous ses appels, et interagit avec l'environnement. Plus coûteux, ils n'en sont pas moins intéressant car en plus de tester les fonctions "en vrai", ils s'avèrent précieux pour tout ce qui est problématiques de performances et de montée en charge (ceci n'est qu'un exemple).
  • Les tests d'interface : un automate simule les actions des utilisateurs et vérifie que les retours de l'application (UI, BDD, fichiers ...) sont corrects.
Il existe effectivement trois grand types de tests mais ce sont : white/grey/black-box. Il ne s'agit pas de délimiter un périmètre (ce qui est dedans, ce qui est en dehors) mais de délimiter la connaissance qu'on a du système.

C'est pourquoi les gens désignent par "intégration" des tests très différents. En général, c'est surtout sur la question du périmètre dont les gens ne sont pas d'accord mais il s'agit probablement de test "boîte grise" dans tous les cas.

Pour la distinction "mock"/"stub" (simulacre/bouchon), ce n'est que mon avis mais un bouchon, c'est un truc figé ; histoire qu'il y ait qqn qui réponde avec (ou sans erreur) à la demande. Les "simulacres" sont beaucoup plus dynamiques : ils permettent notamment d'invoquer un comportement réel et d'espionner le comportement interne.

Citation Envoyé par ZeKiD Voir le message
Manifestement je suis le seul à voir où il a voulu en venir. A savoir que un grand nombre de tests sont réalisés avec des mocks, car la compréhension du code est imparfaite.
En fait, ce n'est pas le fait d'utiliser car la compréhension est imparfaite mais plutôt que l'utilisation des mocks empêchent de parfaire le code parce qu'une tâche censée devenir complexe (le test et donc l'utilisation d'une classe/méthode) ne l'est plus tant que ça et que le besoin en refactoring se fait donc moins sentir.

Citation Envoyé par ZeKiD Voir le message
Evidemment ce n'est pas toujours le cas, mais souvent. Un exemple qui me vient en tête d'une aberration (pour moi!!) d'utilisation des mocks concernent les webservices.
En effet, il n'est pas rare de voir des développeurs utiliser des mocks pour simuler la partie serveur d'un web services, alors qu'un simple appel HTTP avec un assert sur une chaine de caractère de résultat devrait à mon sens être plus judicieux, en plus d'être plus performant. Cela reste mon avis bien entendu.
Cela reste également mon avis mais un test unitaire, doit être unitaire. Si tu commences à dépendre d'un service, je ne vois pas en quoi c'est unitaire. Ca reste un test valable certes, mais pas unitaire.

Citation Envoyé par ZeKiD Voir le message
J'aurai pu troller en précisant que les annotations n'aident pas non plus à savoir ce qui se passe EXACTEMENT dans le code... A mon sens ils vont de pair avec les mocks.
Je trouve pas que c'est du troll mais une question de goût. Je trouve les annotations très pratiques pour la programmation déclarative mais elles ont l'inconvénient d'être complètement lié au code.
Par exemple, en Java (JPA/Hibernate) on peut déclarer le mapping Objet-Relationnel avec des annotations. Très rapide et moins sujet à erreur, cependant cela verrouille l'utilisateur (de la librairie) avec un schéma particulier.
Pour moi, c'est un débat à avoir lors de l'introduction des annotations de manière générale et il convient de décrire les cas d'utilisation de chaque type d'annotation. Ca définit un cadre/contrat sur lequel chacun peut se reposer pour avoir une compréhension générale du système et comment rédiger les classes.

Sinon j'aime bien la programmation orientée aspect, parfois couplé justement avec les annotations pour déposer des marqueurs. Mais pour ne pas lié la librairie et les aspects, il faut alors que le tissage (action d'appliquer l'aspect sur les classes) doit être dynamique.
0  0 
Avatar de ZeKiD
Membre averti https://www.developpez.com
Le 07/05/2015 à 11:27
Manifestement je suis le seul à voir où il a voulu en venir. A savoir que un grand nombre de tests sont réalisés avec des mocks, car la compréhension du code est imparfaite. Evidemment ce n'est pas toujours le cas, mais souvent. Un exemple qui me vient en tête d'une aberration (pour moi!!) d'utilisation des mocks concernent les webservices.
En effet, il n'est pas rare de voir des développeurs utiliser des mocks pour simuler la partie serveur d'un web services, alors qu'un simple appel HTTP avec un assert sur une chaine de caractère de résultat devrait à mon sens être plus judicieux, en plus d'être plus performant. Cela reste mon avis bien entendu.

Je suis assez d'avis avec ce programmeur qui montre que le test est indispensable, et force les développeurs à se poser les questions de savoir ce que je teste EXACTEMENT.
Pas simplement le fait que j'envois une donnée et je reçois la bonne en retour.
Dans le cas des webservices pour moi ce n'est pas un test valable ou plutôt cela correspond à 20% des tests. Les 80% restant devant gérer les limites d'utilisation à savoir : les exceptions "fonctionnelles" (provoqués par le service lui même), les exceptions "techniques" (provoqués par le réseau timeout ou autres), les performances (provoqués par un résultat de recherche vraiment trop important), des choses comme çà.

Enfin voilà quoi...

PS : J'aurai pu troller en précisant que les annotations n'aident pas non plus à savoir ce qui se passe EXACTEMENT dans le code... A mon sens ils vont de pair avec les mocks.
0  1