Partage
  • Partager sur Facebook
  • Partager sur Twitter

Utilité du Test Driven Development

8 septembre 2018 à 16:40:01

Yop.

Ça fait déjà quelques années que je code, mais je "découvre" à peine le TDD, puisque un manager m'a demandé d'implémenter des tests unitaires dans mon dernier projet. (Truc trop long à expliquer, mais c'est en gros un crawler, 90% en Perl, 5% en Python, 5% en batch)

Le "souci" que je rencontre, c'est que toutes les informations et les méthodes que je trouve sur le sujet me semblent difficilement compatibles avec mon code : l'écrasante majorité de mes fonctions ont des valeurs de retour extrêmement variables (L'absence de typage en Perl ne facilite pas les choses.), voire n'ont pas du tout de valeur de retour.

Du coup, trois questions liées :

  • le TDD nécessite-t-il un style de codage particulier pour être efficace ?
  • y-a-t'il un "seuil" au-dessus ou en-dessous (Longueur, qualité du code, nombre de gens qui travaillent dessus..) duquel les bénéfices se font réellement voir ?
  • à part le temps que ça demande et la lisibilité, y-a-t'il une différence fondamentale entre créer des tests unitaires et ajouter des vérifications partout dans les fonctions, dans le code de production lui-même ?
  • Partager sur Facebook
  • Partager sur Twitter
8 septembre 2018 à 20:29:52

Chomp a écrit:

Le "souci" que je rencontre, c'est que toutes les informations et les méthodes que je trouve sur le sujet me semblent difficilement compatibles avec mon code : l'écrasante majorité de mes fonctions ont des valeurs de retour extrêmement variables (L'absence de typage en Perl ne facilite pas les choses.), voire n'ont pas du tout de valeur de retour.

Tu peux tester qu'elles lèvent pas d'exception, ou pas d'exceptions imprévues au moins.

  • Partager sur Facebook
  • Partager sur Twitter

Blond, bouclé, toujours le sourire aux lèvres...

8 septembre 2018 à 22:02:25

LoupSolitaire a écrit:

Chomp a écrit:

Le "souci" que je rencontre, c'est que toutes les informations et les méthodes que je trouve sur le sujet me semblent difficilement compatibles avec mon code : l'écrasante majorité de mes fonctions ont des valeurs de retour extrêmement variables (L'absence de typage en Perl ne facilite pas les choses.), voire n'ont pas du tout de valeur de retour.

Tu peux tester qu'elles lèvent pas d'exception, ou pas d'exceptions imprévues au moins.


(Pas d'exceptions, en Perl, c'est déjà fait pour la partie Python)

C'est pas exhaustif du tout, mais les fonctions avec le plus de "trafic" sont déjà truffées d'exceptions manuelles (Nombre d'arguments, type d'arguments, disponibilité de tous les fichiers d'entrée, profondeur max des structures de données, etc..). Mais bon, c'est en plein milieu du code, on peut pas le tester indépendamment, à moins de créer un script juste pour tester cette fonction. (Et si je me retrouve à copier mon script complet juste pour faire des tests, ça simplifie pas vraiment le tout.)

-
Edité par Chomp 8 septembre 2018 à 22:03:32

  • Partager sur Facebook
  • Partager sur Twitter
9 septembre 2018 à 5:42:10

Hello

> le TDD nécessite-t-il un style de codage particulier pour être efficace ?

Avoir un code correctement découpé aide pas mal. Si chacune de tes fonction n'as qu'une unique responsabilité, elle est bien plus facile a tester.

> y-a-t'il un "seuil" au-dessus ou en-dessous (Longueur, qualité du code, nombre de gens qui travaillent dessus..) duquel les bénéfices se font réellement voir ?

Les bénéfices apparaissent a partir du moment ou le code contient au moins une fonction et qu'il y a une personne qui travaille dessus. Le but est d’être sur que le code fonctionne correctement, donc les bénéfices apparaissent même sur les projets plus petit (après ils sont peut être moins importants).

> à part le temps que ça demande et la lisibilité, y-a-t'il une différence fondamentale entre créer des tests unitaires et ajouter des vérifications partout dans les fonctions, dans le code de production lui-même ?

Oui. Comme tu run tes tests a part, tu peux dire a ton manager "Voila! Mon app est testée et elle fonctionne, voila les résultats des tests." Sans tests, tu peux difficilement certifier de la qualité du code (en terme de conformité j'entends). De plus, les avoirs a part permet de se rendre compte plus facilement qu'on en a oublie un.

> Le "souci" que je rencontre, c'est que toutes les informations et les méthodes que je trouve sur le sujet me semblent difficilement compatibles avec mon code : l'écrasante majorité de mes fonctions ont des valeurs de retour extrêmement variables (L'absence de typage en Perl ne facilite pas les choses.)

Tes fonctions sont peut être trop grosses dans ce cas. ont elles une ou plusieurs responsabilités? Peuvent elle être découpées en fonctions plus petites?

> , voire n'ont pas du tout de valeur de retour.

Si elles modifient l’état de quelque-chose, tu peux faire la vérification que l’état obtenu après avoir appelle la fonction est bien celui attendu.

  • Partager sur Facebook
  • Partager sur Twitter
9 septembre 2018 à 12:14:07

Elried a écrit:

> le TDD nécessite-t-il un style de codage particulier pour être efficace ?

Avoir un code correctement découpé aide pas mal. Si chacune de tes fonction n'as qu'une unique responsabilité, elle est bien plus facile a tester.

J'ajouterais : il faut que la méthode soit appliquée dès le début pour ne pas être coûteuse à mettre en place a posteriori. Comme tout méthode qui permet de faire un suivi à long terme j'ai envie de dire. On se doute bien que si on doit intégrer tout ça après le développement d'une grande partie du programme, il faut réécrire tout ce qui n'a pas été fait dans le passé au moment de la mise en place. Comme on a très souvent autant voir plus de ligne de code pour le test que pour les features quand on vise une forte couverture, bah ... ça demande forcément beaucoup de boulot.

Elried a écrit:

> Le "souci" que je rencontre, c'est que toutes les informations et les méthodes que je trouve sur le sujet me semblent difficilement compatibles avec mon code : l'écrasante majorité de mes fonctions ont des valeurs de retour extrêmement variables (L'absence de typage en Perl ne facilite pas les choses.)

Tes fonctions sont peut être trop grosses dans ce cas. ont elles une ou plusieurs responsabilités? Peuvent elle être découpées en fonctions plus petites?

Je plussoie très fortement et j'ajouterais que c'est même une grande partie de l'objet du TDD : en écrivant les tests avant que la feature soit développée, on écrit les tests qui permettent de valider très précisément cette fonctionnalité et rien d'autre. Deux effets kisskool :

  • comme on a déjà développé les tests, on a déjà une idée assez précise de ce que l'on doit faire pour y répondre,
  • comme on a des tests qui sont précisément prévu pour cette feature, on fera exploser les tests si on commence à faire trop de chose.

Pour moi, le problème que tu as correspond comme le dit @Elried a une fonction qui fait la pluie et le beau temps et ça aurait pu être repéré en TDD.

  • Partager sur Facebook
  • Partager sur Twitter

Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

11 septembre 2018 à 0:23:19

Alors alors alors, trois mises à jour pour répondre "en gros" :

- le problème a été résolu de l'intérieur, mon manager a indiqué précisément à quelle étape il voulait un test, partant de là il était facile de découper la fonction en unités testables.

- Plusieurs de mes fonctions sont trop longues, comme ça a été suggéré (Je le savais déjà, ce projet a été planifié un peu à l'arrache, il est parti d'un script de 100 lignes pour une tâche précise il y a deux mois, maintenant il en fait 3500 en cinq fichiers, et les fonctions principales ont gonflé en taille sans gonfler en simplicité..)

- Pour Perl, j'ai trouvé un outil (Si quelqu'un lit ça un jour : Test:Deep ) qui me permet de tester autre chose que des scalaires, donc plus besoin de découper des fonctions triviales pour les tester. (Et effectivement, je n'avais pas songé à simplement tester l'état avant/après des valeurs éditées dans les fonctions sans retour. Tellement évident que ça me paraissait de la triche.)

Du coup, question en rab : dans un projet standard, le TDD c'est en fonction de la décision du manager, ou c'est la responsabilité du développeur ? Je vais reprendre un projet perso pour bien m'y faire, déjà. ;)

  • Partager sur Facebook
  • Partager sur Twitter
11 septembre 2018 à 9:22:26

Chomp a écrit:

- le problème a été résolu de l'intérieur, mon manager a indiqué précisément à quelle étape il voulait un test, partant de là il était facile de découper la fonction en unités testables.

Encore une fois : d'où l'intérêt du TDD. Par défaut, tes fonctions sont testables puisque tu as déjà écrit les tests des fonctions qui ne sont pas encore présentes :) .

Chomp a écrit:

Du coup, question en rab : dans un projet standard, le TDD c'est en fonction de la décision du manager, ou c'est la responsabilité du développeur ?

Si c'est pas une décision du manager, c'est la responsabilité du développeur de lui faire prendre une décision qui aboutit peu ou prou au même résultat :) . Avoir des tests pour les fonctionnalités du programme c'est vital pour avoir un suivi de son bon fonctionnement. Dans un projet qui contient beaucoup de tests :

  • tu as une bonne estimation de la qualité du logiciel,
  • tu n'as pas peur de faire évoluer même les parties les plus critiques du logiciel.

Le deuxième point est très important. Un logiciel bien testé est, par définition, testable, donc généralement bien organisé donc ce n'est pas trop dur de le lire et le comprendre. Et par dessus tout : il y a des tests, donc si tu fais des modifications qui ne sont pas bonnes, tu le sauras quand les tests exploseront.

  • Partager sur Facebook
  • Partager sur Twitter

Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

13 septembre 2018 à 15:14:21

Donc, noté : la prochaine fois, je me préoccupe du TDD avant de commencer, et j'écris les tests avant d'écrire les fonctions.

La qualité d'un logiciel, je me suis encore jamais posé la question, mais je finirai bien par tomber sur un tuto' pour m'y familiariser.

  • Partager sur Facebook
  • Partager sur Twitter
14 septembre 2018 à 13:49:24

Tout à été dit, mais je rajouterais un petit argument qui explique facilement à un manager en quoi un test unitaire est plus intéressant qu'une fonction avec ses protections intégrées : la régression. https://fr.wikipedia.org/wiki/Test_de_r%C3%A9gression 

Rien de pire qu'une bug qu'on a déjà corrigé, qui réapparaît subitement face à un changement qui, à priori, ne semblait pas avoir d'impact.

L'avantage d'un test unitaire, c'est qu'il fait aussi office de test de régression ! Un test qui appelle une fonction avec une entrée et vérifie son retour, peut être exécuté dans plein de conditions différente. Si un test est suffisamment couvrant, il y a une forte probabilité que si cette fonction (ou une de ses sous routine) est modifiée, et que cette modification à un impact non prévu sur un des tests, celui-ci sera détecté.

C'est d'autant plus vraie dans la "vie" d'un logiciel. On a écrit une fonction il y a 5 ans, on fait une simple modification, et l'un des test qui passait depuis des années est soudainement en erreur. Merci les test, on peut détecter les bug avant que la mise à jour ne soit mise en production. Ce qui aurait été impossible avec des check interne, car ceux-ci sont testé uniquement durant le développement, et donc uniquement avec les entrées fournies par le programmeur, limitées au contexte de la feature en cours de développement. Impossible dans ces condition de repérer une erreur arrivant dans d'autres conditions.

  • Partager sur Facebook
  • Partager sur Twitter
14 septembre 2018 à 15:27:46

Sebajuste a écrit:

Tout à été dit, mais je rajouterais un petit argument qui explique facilement à un manager en quoi un test unitaire est plus intéressant qu'une fonction avec ses protections intégrées : la régression. https://fr.wikipedia.org/wiki/Test_de_r%C3%A9gression 

Rien de pire qu'une bug qu'on a déjà corrigé, qui réapparaît subitement face à un changement qui, à priori, ne semblait pas avoir d'impact.

L'avantage d'un test unitaire, c'est qu'il fait aussi office de test de régression ! Un test qui appelle une fonction avec une entrée et vérifie son retour, peut être exécuté dans plein de conditions différente. Si un test est suffisamment couvrant, il y a une forte probabilité que si cette fonction (ou une de ses sous routine) est modifiée, et que cette modification à un impact non prévu sur un des tests, celui-ci sera détecté.

C'est d'autant plus vraie dans la "vie" d'un logiciel. On a écrit une fonction il y a 5 ans, on fait une simple modification, et l'un des test qui passait depuis des années est soudainement en erreur. Merci les test, on peut détecter les bug avant que la mise à jour ne soit mise en production. Ce qui aurait été impossible avec des check interne, car ceux-ci sont testé uniquement durant le développement, et donc uniquement avec les entrées fournies par le programmeur, limitées au contexte de la feature en cours de développement. Impossible dans ces condition de repérer une erreur arrivant dans d'autres conditions.


Je t'avoue que tout ça me parle assez peu ;)

La régression, j'en entends parler, mais c'est une autre équipe qui s'en charge dans le projet principal. Bref, je découvre.

  • Partager sur Facebook
  • Partager sur Twitter