L'excès de tests unitaires nuirait au développement agile
Ils seraient favorisés par rapport aux tests d'intégration

Le , par Arsene Newman, Expert éminent sénior
Bien souvent, le développement agile mise sur le développement piloté par les tests (TDD). Aujourd’hui, Mark Balbes, un des membres les plus éminents de Asynchrony Solutions et expert en développement logiciel et en gestion de projet agile, nous livre sa vision des faits en ce qui concerne le TDD.

L’expert estime qu’actuellement, le développement agile use excessivement du TDD, les développeurs ont alors tendances à créer trop de tests surtout avec la multitude d’outils existants sur le marché. Or, une écriture et un choix plus judicieux des tests à utiliser seraient nettement plus bénéfiques pour le développement agile.

En effet, l’apport du TDD est non négligeable, ce dernier préconise l’utilisation de tests unitaires pour vérifier le bon fonctionnement/comportement d’une classe. Les développeurs créent alors des tests unitaires pour chaque entité de leur programme, mais dans certains cas, les tests unitaires s’avèrent inefficaces. Il faut donc songer à utiliser d’autres tests comme les tests d’intégration qui permettent de vérifier si le programme fait le travail souhaité. Il s’agit de vérifier si l’interaction entre les différents objets se fait correctement et se conclut par une exécution correcte du programme.

Ainsi, les tests unitaires diffèrent sensiblement des tests d’intégration, ils permettent de vérifier le fonctionnement de chaque classe indépendamment des autres. Toutefois, ils ne garantissent pas l’interaction correcte des objets. Pourtant, le développeur se préoccupe en premier lieu du bon fonctionnement du programme dans son ensemble. C’est là qu’il y aurait contradiction avec les pratiques de certains.

L’expert recommande donc aux développeurs de s’affranchir d’une utilisation trop récurrente des tests unitaires qui tirent leur source du TDD et d’utiliser à bon escient chaque type de test : des tests unitaires pour les classes qui traitent des données et des tests d’intégration pour les objets qui interagissent entre eux et qui modifient/déplacent des données, car après tout l’esprit agile c’est aussi une souplesse de l’esprit.

Source : Billet de blog de Mark Balbes

Et vous ?

Qu’en pensez-vous ?


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse

Avatar de Luckyluke34 Luckyluke34 - Membre émérite https://www.developpez.com
le 26/05/2014 à 11:53
And why did we do this? We don't really care about how the objects work together. We care that the system behaves correctly as a whole.

Sous une apparence de bon sens, cette phrase cache une fausse bonne idée qui me parait dangereuse si on l'applique à la lettre.

Si on a un graphe de 2, 5, 10 objets, et qu'on se fixe comme unique objectif de vérifier ce qui se passe à chaque bout de cette chaine, on va être tenté de ne tester que les cas nominaux et quelques cas d'erreur les plus courants, sans se poser la question de la validité des objets intermédiaires dans des scénarios très spécifiques. Les tests unitaires ont cette vertu qu'ils nous forcent à nous intéresser à chaque petit composant et nous interroger sur le contrat qu'il doit fournir, le protocole d'échange de messages avec ses collaborateurs, les plages de valeurs qu'il peut et ne peut pas accepter, etc. A l'inverse, plus les tests d'intégration portent sur un gros graphe d'objets, plus il est difficile d'imaginer des scénarios et des combinaisons qui sortent des sentiers battus et provoquent une erreur inattendue. Même en supposant qu'on arrive à les discerner, il sera plus difficile de mettre notre grappe d'objets non isolés dans la configuration voulue, aboutissant en général à des tests lents et avec une étape de setup très compliquée.

Quand on regarde les récents bugs retentissants dans OpenSSL (HeartBleed), dans iOS, ils auraient pu être évités grâce à des micro-tests ciblés qui vérifient la validité d'une unité de code vis-à-vis de cas non nominaux.

Il y a une autre (meilleure ?) façon de s'assurer de cette validité basique du comportement d'un objet, c'est l'approche Design By Contract : rajouter des pré- et post-conditions aux méthodes pour spécifier ce qu'elles peuvent accepter et ce qu'on attend d'elles. Les tests/spécifications unitaires deviennent alors intégrés au code de production.

Bien sûr que ce qui nous intéresse, c'est que le système entier se comporte correctement, mais le diable se trouve dans les détails de ce "comportement correct". Dans quels scénarios ? Avec quelles données ? Quel niveau de tolérance aux défaillances matérielles ou logicielles d'autres systèmes ? Pour moi, les tests unitaires permettent de débusquer tous ces lièvres bien mieux que des tests plus larges.
Avatar de la.lune la.lune - Membre chevronné https://www.developpez.com
le 26/05/2014 à 17:42
Citation Envoyé par Arsene Newman  Voir le message
L’expert recommande donc aux développeurs de s’affranchir d’une utilisation trop récurrente des tests unitaires qui tirent leur source du TDD et d’utiliser à bon escient chaque type de test : des tests unitaires pour les classes qui traitent des données et des tests d’intégration pour les objets qui interagissent entre eux et qui modifient/déplacent des données, car après tout l’esprit agile c’est aussi une souplesse de l’esprit.

Mais une souplesse de l'esprit de ne veut pas dire livrer un produit avec des bugs, ceci est totalement contre la démarche qualité du projet. Si on se focalise sur les testes d’intégrations et on ne voit que la bonne marche du programme selon le but spécifique du client, Il suffit qu'on pense à l'évolution du projet pour qu'après ces bug apparaissent.

Vouloir faire entrer l'agile même dans le fond du métier du codage c'est passer à côté de la plaque. L'agilité c'est dans le processus et non pas sur les choses clés du codage et qui sont fortement recommandé par toute démarche qualité.

Il ne faut pas voir teste unitaire comme juste le fait d'écrire toute une séries de testes unitaire automatisés , mais le fait de chaque méthode soit testé si elle marche correctement selon tous les types de données possibles en paramètre et les types normalement attendus, comme on dit teste unitaire: c'est tout simplement le teste d'une petite unité du programme. Alors selon lui, il veut qu'on diminue ça et on privilégie la partie intégration entre plusieurs unités du programmes
Mais c'est exploser le temps de la correction de bug, voir impossible de connaitre d'où vient certains bugs.

Si j'ai une méthode m1 et m2 qui ne sont pas bien testés à tous les coups et je les intègre ailleurs pour donner le résultat d'une fonctionnalité X, alors je fais que je m'intéresse au fait que la fonctionnalité X fonctionne correctement et que ça suffit comme teste de m1 et m2, c'est grave Car il suffit d'avoir à intégrer m2 avec un m3 d'autre part pour une fonctionnalité Y pour que j'obtienne un bug, oui m2 cachait un bug qui n'est pas vu quand j'ai testé X.

Pire encore, je vas revenir pour corriger le bug caché de m2, je vais en produire d'autres sans me rendre compte. oops : X ne fonctionne pas correctement Régression !!! Ils ne sont pas fous ceux qui ont pensé au outils d’intégration continue, mais comment les utiliser si on a pas une base de testes unitaires pour tous les unités du programme? C'est de la merde.
Citation Envoyé par Arsene Newman  Voir le message
Qu’en pensez-vous ?

Qu'on ne fait qu'encourage les mauvaises pratiques, et un ingénieur qui apprend un maçon comment bien placer ces briques. C'est fini on ne fait que dire bonjour aux
Avatar de DonQuiche DonQuiche - Expert confirmé https://www.developpez.com
le 26/05/2014 à 19:33
Citation Envoyé par Arsene Newman  Voir le message
En effet, l’apport du TDD est non négligeable, ce dernier préconise l’utilisation de tests unitaires pour vérifier le bon fonctionnement/comportement d’une classe.

Je ne suis pas d'accord avec cette affirmation : si tel était le cas il n'y aurait pas d'intérêt à écrire les tests avant. Si le test-driven development préconise d'écrire d'abord les tests c'est parce que cela force le développeur à partir du haut (le contexte d'utilisation de la classe, les spécifications, etc) plutôt que du bas (l'algorithme). Dans ce contexte le test ne sert pas à tester mais d'abord à concevoir !

Et pour ce qui est du choix des tests, il y a effectivement une gamme d'outils disponibles dont les test unitaires ne sont qu'un maillon et pas toujours indispensables ou judicieux (et encore moins souvent le plus judicieux si l'équipe a décidé d'allouer peu de moyens aux tests).
Avatar de el_slapper el_slapper - Expert éminent sénior https://www.developpez.com
le 26/05/2014 à 21:34
Pour filer la métaphore du maçon : le mur doit être bien construit, et chaque brique doit être conforme.
Avatar de transgohan transgohan - Expert confirmé https://www.developpez.com
le 26/05/2014 à 23:48
J'ai envie de dire que cela dépend de quel projet on parle... Il a suivi quels types de projets ce monsieur ?
Les TU c'est bien mais pas indispensables sur les énormes projets (dans ce cas là c'est souvent une perte de temps à cause des refactorings constants), on leur préférera les tests fonctionnels système.
Mais sur des petits et moyens projets il sera bête de s'en passer, c'est une bonne assurance qualité quand c'est bien rédigé.
Avatar de Jay13mhsc Jay13mhsc - Membre du Club https://www.developpez.com
le 29/05/2014 à 22:08
Et un jour, @jbrains a dit : http://www.jbrains.ca/series/integra...sts-are-a-scam

On a jamais dit qu'un TU portait sur une seule classe...
Quand on teste, on le fait sur une interface stable. Point.
Avatar de Matthieu Vergne Matthieu Vergne - Expert confirmé https://www.developpez.com
le 01/06/2014 à 15:10
Dans l'ensemble, ça part d'une bonne intention : trop de quelque chose, c'est comme pas assez, ce n'est jamais bon. Le principal message (de ce que j'ai compris de l'article) est que certains croient dur comme fer à la primauté des test unitaires et mettent des ressources à l'excès sur ce point. Ce que préconise ce monsieur est d'être moins fanatique (pour ceux qui le sont) et de répartir les efforts sur plusieurs types de test, ce qui en soit me semble être censé.

Cela dit, je rejoins le point de certains : il ne faut pas tomber dans l'excès inverse en concentrant tous ses efforts sur des tests d'intégration sans se préoccuper du bon déroulement interne. Sinon on fait de la programmation génétique (création et évolution automatique de programmes) en cherchant à maximiser les tests d'intégration qui passent. Inutile de savoir programmer, on fait des tests d'intégrations à gogo et basta.

De la même manière qu'on prouve un théorème pas-à-pas, on fait un programme qui marche bien pas-à-pas. Les briques internes doivent être bien faites pour que l'ensemble tienne, tout comme l'ensemble doit être organisé correctement pour que ça ressemble à quelque chose.

Pour ma part, j'estime qu'il est stupide de faire une différence entre tests unitaires et tests d'intégration (et autres types de tests) car l'idée véhiculée en général est que tout projet doit avoir une hiérarchie de tests donnée, ce qui à tendance à foirer lamentablement si on le prend à la lettre. Si on développe une lib, qu'est-ce que ça veut dire d'avoir des tests d'intégration ? Est-ce à la lib de faire ces tests, et donc de vérifier dans tous les cas où elle peut-être utilisée si ça marche correctement ? Infaisable. Est-ce au programme qui l'utilise de le vérifier ? Mais si oui, alors qu'est-ce qu'un test d'intégration au niveau de la lib ? Ça ne peut pas être un test qui vérifie qu'une sous-lib (lib pour la lib) s'intègre correctement, vu que ça serait au même niveau que des tests unitaires, hors un test d'intégration est censé être plus haut niveau.... {_~_}

De mon point de vue, un test permet de vérifier que tout se passe bien dans un contexte donné, que ce soit un contexte très bas niveau ou très haut niveau. Quand je programme, je design mon programme en identifiant des concepts et leurs relations pour établir des interfaces, en les réduisant au minimum pour avoir quelque chose de simple. Quand je les implémentent, si j'ai besoin de fonctionnalités avancées (et que je n'ai pas de lib pour le faire), je réfléchis séparément à ces fonctionnalités en établissant des concepts et leurs relations pour établir leurs interfaces, que j'implémente, et ainsi de suite. Je n'hésite pas d'ailleurs à faire des projets séparés quand je sens que ça peut être réutilisé. À chacun de ces niveaux, je fais des tests qui correspondent au contexte précis que je design et que j'implémente. De ce fait, les tests effectués à bas/haut niveau correspondent à des tests unitaires/d'intégration, mais dans l'esprit ce ne sont ni plus ni moins que le même genre de tests que je fais dans différent contextes : ils servent à vérifier que l'implémentation de mes interfaces, au niveau donné, correspond à mon cahier des charges pour ce niveau, point final. C'est une approche de test très modulaire, autant que la modularité du programme en lui-même, et qui permet de se focaliser sur un contexte donné sans commencer à réfléchir à comment il est censé interagir une fois associé à telle ou telle autre fonctionnalité. Sinon on fait du code spaghetti non-maintenable et très dur à reprendre.
Avatar de yashiro yashiro - Membre régulier https://www.developpez.com
le 15/06/2014 à 8:38
Je pense pour ma part qu'il faut dissocier le principe des tests unitaires/intégration de leurs usages par les développeurs. C'est pas parce que certains développeurs utilisent peu/trop/mal ces types de tests qu'il sont bon/mauvais en soi,
De plus, je suis aussi convaincu que plus le projet est gros, plus il faut tester les différents composants de façon unitaire et intégrée selon les chemins nominaux et alternatifs.
Mais le plus important pour moi c'est que dans un projet, il faut définir des normes de développement qui permettront de décrire (entre autres) comment un code doit être écrit et testé. Un développeurs de l'équipe ne devrait pas écrire un(des) test(s) selon son bon vouloir, mais il doit être guidé par une norme de développement définie en amont et contrôlée automatiquement par des outils d'intégration continue.

Dans les projets dont je suis responsable, les tests unitaires sont hyper important parce qu'ils me permettent de m'assurer du bon fonctionnement des différents composants et les tests d'intégration me permettent de valider leur fonctionnement couplés en considérant que s'il ya des erreurs, celles-ci ne viennent pas du fonctionnement propre des composants mais plutôt de leur intégration: de ce fait, je vais beaucoup plus vite dans la localisation des bugs et dans leur correction.
Avatar de souviron34 souviron34 - Expert éminent sénior https://www.developpez.com
le 16/06/2014 à 10:23
Je recopierais ici ce que j'ai mis de l'autre côté sur l'apprentissage :

Je ne vois pas pourquuoi associer les TU et agilité : les TU proviennent du cycle en V... C'est une bonne chose dans certains cas, une mauvaise dans d'autres. De manière générale c'est à mon avis une très mauvaise manière de faire de leur accorder la primauté sur les tests fonctionnels, et de garder la rigidité des cycles en V sur ce point (que ce soit en doc ou en programmation)

Les TU sont utiles pour les opérations complexes, les unités complexes impliquant un calcul particulier, l'application d'une méthode particulière.. Faire des TU pour vérifier que la fonction A+B fait bien A+B est stupide, et une perte de temps et d'argent phénoménale - ou alors c'est que vous n'avez pas confiance dans votre équipe, et alors votre équipe n'est en rien basée sur l'Agilité.

D'autre part, la documentation des TU doit être réduite à sa plus simple expression : "passé le test le DD/MM/YYY à hh:mm", sans plus.. En mettre plus est bêtement du recopiage du cycle en V dans sa plus lourde et pénible - et lente - expression..

Les TU sont un reliquat du cycle en V, qui simplement reposent sur 4 éléments qui ne font pas partie de l'Agilité mais du modèle en cascade : d'une part que toute personne est remplaçable à tout moment, secondo que tout doit être documenté/analysé avant de le faire, tertio que il y a un ordre logique et immuable dans les opérations, et quarto que le programmeur est "irresponsable" et que seule la doc et le chef sont responsables...

Y accorder une importance en termes de projet est stupide et anti-agilité : soit les personnes de l'équipe sont responsables, et alors on leur fait confiance pour faire des TU lorsque ils le jugent nécessaire - unité complexe -, et alors on est agile, soit les personnes de l'équipe sont irresponsables, et alors on doit surveiller de l'extérieur leur avancement et leur programmation, et on oblige à faire tous les TU documentés de chaque unité, et alors on est dans un schéma anti-agilité.

Ceci est mon opinion et je la partage
Avatar de Marco46 Marco46 - Expert éminent https://www.developpez.com
le 16/06/2014 à 11:11
Citation Envoyé par souviron34  Voir le message
Je ne vois pas pourquuoi associer les TU et agilité : les TU proviennent du cycle en V... C'est une bonne chose dans certains cas, une mauvaise dans d'autres. De manière générale c'est à mon avis une très mauvaise manière de faire de leur accorder la primauté sur les tests fonctionnels, et de garder la rigidité des cycles en V sur ce point (que ce soit en doc ou en programmation)

Parce que les TU rendent possibles la souplesse de l'agilité. Tes tests te permettent de détecter les problèmes avant de contaminer la base de source avec des régressions. En gardant une base de source propre tu peux déployer n'importe quand.

Citation Envoyé par souviron34  Voir le message
Les TU sont utiles pour les opérations complexes, les unités complexes impliquant un calcul particulier, l'application d'une méthode particulière.. Faire des TU pour vérifier que la fonction A+B fait bien A+B est stupide, et une perte de temps et d'argent phénoménale -

Ils sont obligatoires pour les fonctions complexes et ils sont très utiles partout. Evidemment tester un accesseur n'a pas de sens. Tester la bonne affectation d'un accesseur en a par contre.

Citation Envoyé par souviron34  Voir le message
ou alors c'est que vous n'avez pas confiance dans votre équipe, et alors votre équipe n'est en rien basée sur l'Agilité.

C'est pas une question de confiance, tout le monde fait des erreurs. Les TU permettent de les voir.

Citation Envoyé par souviron34  Voir le message
Les TU sont un reliquat du cycle en V, qui simplement reposent sur 4 éléments qui ne font pas partie de l'Agilité mais du modèle en cascade : d'une part que toute personne est remplaçable à tout moment, secondo que tout doit être documenté/analysé avant de le faire, tertio que il y a un ordre logique et immuable dans les opérations, et quarto que le programmeur est "irresponsable" et que seule la doc et le chef sont responsables...

Un test unitaire sert à détecter les régressions.

Citation Envoyé par souviron34  Voir le message
Y accorder une importance en termes de projet est stupide et anti-agilité : soit les personnes de l'équipe sont responsables, et alors on leur fait confiance pour faire des TU lorsque ils le jugent nécessaire - unité complexe -, et alors on est agile, soit les personnes de l'équipe sont irresponsables, et alors on doit surveiller de l'extérieur leur avancement et leur programmation, et on oblige à faire tous les TU documentés de chaque unité, et alors on est dans un schéma anti-agilité.

Aucun rapport avec la notion de responsabilité. Je vais me répéter, l'erreur est humaine, tout le monde en fait, et les TU servent à voir les régressions. Dans un contexte agile où l'on change souvent de priorité, où l'on change constamment le contenu, le refactoring est permanent, et les TU sont un outil pour aider les devs à faire ce refactoring.

Ca n'a absolument rien à voir avec ce que tu racontes.

Pour moi tu es tout simplement hors-sujet.
Offres d'emploi IT
Stagiaire Développement
I&E - Ile de France - Paris
Développeur java-j2ee editeur de logiciel en saas
MATIERE GRISE - Ile de France - Paris (75000)
Développeur frontend (H/F)
FACILOGI - Ile de France - Paris (75000)

Voir plus d'offres Voir la carte des offres IT
Contacter le responsable de la rubrique Accueil