JeuWeb - Crée ton jeu par navigateur
L'utilité du test unitaire - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : L'utilité du test unitaire (/showthread.php?tid=6973)

Pages : 1 2 3 4 5 6


RE: L'utilité du test unitaire - Sephi-Chan - 26-08-2013

Moi j'ai arrêté quand j'ai constaté l'obsession pour la preuve mathématiques. :p


RE: L'utilité du test unitaire - niahoo - 26-08-2013

(26-08-2013, 06:27 PM)Xenos a écrit : ça va te tomber dans le coin de la figure, et c'est généralement là que démarrent les bidouillages et arrangements boiteux qui finissent par massacrer un projet (non?).

Ben non :
-- Oh tiens ça bug quand on met '8' ici .
-- Alors balance 8 dans la fonction et je trace tous les appels pour voir ... hmm ça passe par 'multiplie' et par 'machintruc'
-- Ok je teste 8 en entrée sur ces deux fonctions .. ça passe pas sur 'multiplie' !
-- Ok le bug est là, je le corrige ... ah ouais en fait ça marche pas dès qu'on dépasse 9 en sortie.
-- Bon bah c'est corrigé .. alors Xenos ça avance ta preuve mathématique du Hello World pour le projet sur 3 ans là ... C'était quoi déjà ?
-- Une todolist en javascript ... from scratch Smile


RE: L'utilité du test unitaire - Xenos - 26-08-2013

Par "preuve", j'entends une démonstration exacte et exhaustive, basée sur la lecture et la compréhension du code source; ce qui est assimilable à une preuve (démonstration) mathématique, où les hypothèses sont le code source.
Je n'ai pas d'exemple en entreprise, seulement en école. Il fallait non seulement concevoir le projet (UML) et l'implémenter (comme à peu près partout je suppose), mais également, prouver que l'algorithme et les méthodes sont fiables (à grand coups de "quelque soit l'entrée X blablabla").


Bah, alors si les tests ne sont pas là pour prouver qu'un code marche, ils sont là pour quoi? Pourquoi n'aurai-je pas de clients? Entre "eh, j'ai fait des tests, et cela marche, mais pour les 99.999% des cas non testés, ben je ne sais pas trop" et "mon architecte, avec l'aide du mathématicien, ont démontré que le code marchera toujours", y'a une sacrée marge, non? Il a quand même une notion de garantie dans la démonstration (ou preuve) que je ne retrouve pas dans le test simple.

Citation :Pour mon code, ta preuve n'est pas recevable
Pourquoi? J'ai pas dit que this.x aurait la même valeur qu'après le premier "set()". En revanche, au vu du code, je peux faire l'hypothèse que this.x a la valeur assignée leur du dernier appel à set() ou la valeur null (c'est pas génial comme hypothèse et même complètement inutile, mais je peux la faire).

Pas faux, n'ayant pas donné de spécif, preuve ou test n'ont aucun sens. J'ai justement induis que plus() devait sommer deux nombres et renvoyer leur somme, j'ai fais exactement la même chose qu'un test qui induirait que la fonction marche.

Et tu te dis peut-être que la preuve mettrai des mois ou des années à se faire... C'est peut-être juste un manque de pratique Confusediffle: De toute façon, dans tous les cas, ma preuve une fois faite est terminée et enterrée, tandis qu'avec l'approche des tests, il faut de façon continue "surveiller" et corriger le système. Le test a une sorte d'approche "blacklist" là où la preuve est plus "whitelist".

Après, ok, ce qui m'échappe peut être c'est l'approche "informatique technique", où un truc boiteux vaut mieux que prendre le temps de faire un truc robuste...

Belle trouvaille que ce lien, niahoo. D'ailleurs, sur des systèmes parallèles, vous vous fiez là encore à des simples "tests"?!

/PS
Citation :Mais quand les tests sont bien conçus, les satisfaire satisfait aussi le besoin.
Ok. Tu me payes quoi si je te prouves que quelque soit les N tests que tu feras, si jamais l'élément testé accepte au moins N+1 état d'entrée, alors l'élément peut être buggé et le besoin insatisfait?


RE: L'utilité du test unitaire - Sephi-Chan - 26-08-2013

C'est ça le truc : c'est qu'on développe, on est pas forcément là pour prouver quoi que ce soit.

On conçois une méthode pour supporter des arguments définis. On s'en fout que ça marche pour tout l'univers : il suffit que ça fonctionne dans les cas qu'on a prévu d'utiliser. Et les tests permettent de communiquer ça à ceux qui utiliseront le code.

Si j'implémentais une méthode qui retourne la valeure absolue d'un nombre, je testerais 3 cas : -1, 0, et 1. En voyant ça (couplé à sa documentation), à toi de l'utiliser en bon père de famille. Après, rien ne te dit que je ne t'ai pas fait une blague, et que absolute(7) renvoie "trololol".


RE: L'utilité du test unitaire - Xenos - 26-08-2013

Ok.
J'aurai quand même tendance à demander aux développeurs de prouver que leur code respecte ce que la spécification a dit (mais après, je suis peut-être un tyran sanguinaire!), et généralement, la spécification ne décrit pas les cas "un à un", ce qu'un test fait.

(conclusion: je n'aime pas les tests, je n'aime que les démonstrations :cogneSmile


RE: L'utilité du test unitaire - Argorate - 26-08-2013

Moi de la façon dont Sephi m'a présenté la chose lorsque j'ai commencé à en faire n'est pas la même que toi Xenos. Je pense comprendre ce que tu veux dire et dans l'absolue tu as raison, mais c'est justement pas comme ça qu'il faut le voir.

Ma façon de voir les tests unitaires c'est : je pose les cas qui doivent marché tel que j'aimerais qu'il marche, puis je test les cas connu qui ne doivent pas marché, et je m'assure que tout ça soit ok.

Puis si y a un bug, je crée la nouvelle "règle" en faisant le test qui déclenche le bug, je m'assure que le bug bug, puis je fais une correction qui fait que maintenant ça fonctionne correctement.

Alors oui, peut importe la longueur de mes "règles"/tests, il existe peut être une façon de faire, un cas particulier qui ne marche pas, peut être qu'il y a des cas bugé que je n'ai pas encore trouvé, mais ce n'est pas grave, le jour où il y a un bug, tu ajoutes la regle et tu fixe la chose, et tu retrouves un truc fonctionnel.

Si maintenant tu es en train de dire que parce qu'on est jamais sur (je parle pas pour des truc triviaux évidemment), qu'on est pas à l'abri d'un bug sortie d'on ne sait où, alors il ne faut pas perdre du temps à tester et sécuriser au maximum, je ne pense pas que ce soit la bonne conclusion.

Peut être que c'est pas idéal, ni parfait dès le début, mais la puissance qu'il y a avec les tests unitaires, c'est que chaque fois tu rajoutes une règle qui sécurise encore plus, et plus le temps passe, plus tu trouves de bug, et plus ton appli est en béton car en relançant tous les tests, tu sais si tu as cassé un truc ou pas, et en plus tu évites de retomber sur d'anciens bugs (et refaire les même fixe). Tu es effectivement pas sûre à 100%, tu n'as pas prouvé qu'il y avait aucune possibilité de bug, mais tu as, a priori réglés tout les cas.
Là au moins, tu sais que tu ne mets pas du scotch, tu bétonnes, alors oui tu bétonnes peut être pas tout d'un coup selon la complexité de la chose testé, mais ça ne peut qu'aller mieux avec le temps, c'est ça qui est bon, tu gardes la validité acquise tout au long de la vie de ton projet, et si tu ajoutes les cas quand tu trouves des bugs comme je le disais, tu t'approches toujours plus de la perfection, mais peut être, il est vrai, sans jamais l'atteindre?

Au final si ce que tu veux savoir c'est si sous prétexte que la perfection est inatteignable, il ne faut pas essayer de l'atteindre, ma réponse ne peut être que non !


RE: L'utilité du test unitaire - niahoo - 26-08-2013

Citation :J'ai justement induis que plus() devait sommer deux nombres et renvoyer leur somme

J'ai toujours pas compris pourquoi ma fonction ne faisait pas d'addition ... la spec c'est d'implémenter l'addition pour un objet de type nombre.

Citation :Et tu te dis peut-être que la preuve mettrai des mois ou des années à se faire... C'est peut-être juste un manque de pratique
Mais je t'en prie, fais une fonction qui fait une requête mySQL et prouve que l'algorithme est correct.

Citation : De toute façon, dans tous les cas, ma preuve une fois faite est terminée et enterrée, tandis qu'avec l'approche des tests, il faut de façon continue "surveiller" et corriger le système.
Ce qu'il y a de bien avec l'approche des tests c'est qu'elle est conçue pour les bon développeurs, ce qui font évoluer leur code, le maintiennent, font des applis qui se vendent et dont le code est utilisé par des appels de plus en plus variés. Pas pour des mathématiciens qui sauraient apporter la preuve que chacun de leurs algos est correct puis enterreraient leur code comme tu dis.

De plus tu ne réponds que sur les test du code pour le débug, qu'as tu as dire pour le reste, ne penses-tu pas que ce sont déjà des éléments suffisants pour tester le TDD ?

Citation :Ok. Tu me payes quoi si je te prouves que quelque soit les N tests que tu feras, si jamais l'élément testé accepte au moins N+1 état d'entrée, alors l'élément peut être buggé et le besoin insatisfait?

je te paierai rien mais je serai très impressioné Smile Voici une fonction qui calcule la longueur d'une liste. (x:xs) signifie qu'on bind x sur le premier élément de la liste et xs sur le reste de la liste.



Code :
len :: [a] -> Int
len [] = 0
len (x:xs) = 1 + (len xs)

comme test, je propose simplement :

Code :
assert ((len []) == 0)
assert ((len [[]]) == 1)

si tu match (x:xs) sur [1], x vaut 1 et xs vaut []


RE: L'utilité du test unitaire - Ter Rowan - 26-08-2013

ok je comprends mieux

bon ben ma démonstration que la preuve est un mauvais choix dans une très grande majorité des cas est ultra simple :

les compétences / connaissances / capacités intellectuelles nécessaires à un type capable de prouver le fonctionnement correct d'une application de taille moyenne correspondent à très peu de ressources

y a bien les trois quarts des ingénieurs qui seront incapables de le faire ou du moins de le faire correctement et rigoureusement sur la durée (moi le premier)

de fait, pour réaliser des preuves dans le développement je dois recruter un, deux trois mathématiciens / ingénieurs à profil assez rares (centrale, x, normal sup, super profil de fac, ...)

est ce que je vais recruter ces profils en quantité suffisante pour prouver l'ensemble de mes programmes ==> non

est ce que je vais pouvoir conserver ce type de profil pendant un temps suffisament long avant qu'ils ne souhaitent évoluer vers d'autres fonctions (car comme dans tout métier, au delà du diplome, on doit investir dans la formation, etc.. c'est pas juste six mois) ==> non

est ce que ce type de profil ne serait pas plus intéressant dans d'autres fonctions plus rentable de l'entreprise que la validation qualité d'un code ==> évidemment

conclusion, en tant que manager, je reste sur des stratégies de test (en dehors de cas spécifique, logiciel d'avions, exploration spatiale, nucléaire, etc...) même si celles ci ne garantissent pas à 100% les programmes

un bon artisan doit choisir des outils adaptés à chaque situation


RE: L'utilité du test unitaire - Xenos - 26-08-2013

D'accord pour l'argument économique (mais je trouve dommage que cela tende à "dériver" en un "faites tous des tests" plutôt qu'en un "à défaut de faire des preuves, faites des tests"). J'objecterai quand même qu'un ingénieur qui te fais la preuve de tous les éléments du projet peut être moins cher qu'un stagiaire en continue pendant 3 ans (même en payant le stagiaire 10x moins mais là, je compte hors charges patronales). Un peu comme "locataire vs propriétaire": la location coute pas grand chose, mais elle coûte chaque mois, alors qu'une fois propriétaire (investissement), c'est "à vie".
Mais, ok, l'argument économique est intéressant (dans le cas d'une entreprise qui embauche, pas dans un cadre perso donc).

Citation :quelque soit les N tests que tu feras, si jamais l'élément testé accepte au moins N+1 état d'entrée, alors l'élément peut être buggé et le besoin insatisfait?
Attention à tous les mots Wink

Pour la démonstration:
Citation :E l'élément "parfait": il fait exactement ce qu'on veut quelque soit l'entrée
Soit F l'élément à tester
{Ti} l'ensemble des N tests passés avec succès par F

F accepte N+1 entrées, donc il existe une {e} entrée qui n'est pas testée (au moins).
Dans F, j'ajoute un "if then else": si l'entrée de F vaut {e}, alors je renvoie une valeur bidon, différente de celle de E.
Sinon, si l'entrée fais partie des tests, je renvoie la valeur de E.
Oui, c'est schématiquement la démonstration du troll... Mais le troll peut être involontaire (je suis sûr que vous vous êtes déjà arraché les cheveux, ou ce qu'il en reste suivant les gens, alors que l'erreur était "toute bête": une erreur de signe, une parenthèse qui saute...).

Pour reprendre le code de l'exemple:
On a 2 tests, et la fonction len a des tas d'entrées possible. Voici une fonction len qui répond aux tests sans faire ce qu'on attend vraiment d'elle (calculer la longueur de la liste):
Code :
len [] = 0
len (x:xs) = 1

Alors, oui, quand c'est délibéré de la part du développeur, c'est franchement malhonnête et c'est du sabotage. Mais si tu dis à un sous-traitant "voici mes spécifications: la fonction doit passer ces tests avec succès", alors si le sous-traitant te file un code moisi comme mon précédent exemple, tu n'auras aucun recours (et ça coutera des sous, contre-argument économique Wink).


Si j'ai bien compris:
* len est une fonction prenant une liste de trucs en entrée, et renvoyant un entier Int.
* Si l'entrée est une liste vide, len renvoie 0
* Si l'entrée est une liste d'au moins un élément ( en supposant que si la liste n'a qu'un élément, alors x:xs assignera l'élément à x et [] à xs), alors on renvoie 1 + len(xs)

Ok, ton teste passe pour [] et [[]]. Les entrées possibles pourraient être considérées comme illimités (ou disons trop nombreuses pour être dénombrables).
Quid d'une liste de plus de 2^32 éléments (qui génère un dépassement d'entier de la sortie)? Quid d'une liste de N éléments assez grande pour bousiller la pile d'appel?

Ce qui me gène avec cette approche du test, c'est que le développeur est incapable de dire quels sont les cas qui marchent. Il a légitimement le droit de dire "ça marche avec [] et [[]]" mais l'induction "ça marche pour toute liste" n'est pas prouvée: on a passé sous le tapis des hypothèses (taille max de la liste). Le jour où l'utilisateur du code sortira de ces hypothèses (dont il n'a pas eu connaissance) marquera l'apparition d'un bug, difficile à tracer.

Il me semble donc dommage de dire à tous les artisans de bricoler avec des outils du Dimanche juste parce que tous les artisans n'ont pas forcément les moyens d'acheter de grosses machines.


RE: L'utilité du test unitaire - niahoo - 26-08-2013

haha je savais que tu proposerais comme exemple une liste si longue que le PC pète un câble. Malheureusement pour toi ça ne s'appelle pas prouver qu'un algorithme est correct ou non, ça s'appelle ne pas avoir un hardware adapté à ses besoins. Le théorème de Pythagore est prouvé mathématiquement mais si tu fais une fonction qui l'implémente et que tu lui balance un triangle avec des côtés trop grands ou je ne sais quoi ça ne signifie rien. Mathématiquement l'algorithme est toujours valide, c'est ton hardware qui ne sait pas le gérer. Quant au dépassement d'entier c'est possible mais pas dans le langage dans lequel j'ai implémenté mon exemple.

Maintenant j'aimerais que tu me montres comment avec une démonstration mathématique on prend en compte le dépassement de pile =D Je suis sérieux car là réside toute la surpuissance du test mathématique par rapport à une implémentation correcte et des tests bien pensés.

Quant au code que tu montres, c'est moi qui ait donné l'implémentation. C'est pas toi déjà qui parlait de malveillance involontaire ? Là le troll involontaire Smile à quand le braquage de banque involontaire ? :p

Quand on fait du TDD on s'inscrit dans une démarche de qualité. Si tu me livres ce "code" et que j'ai un bug, je tracerai l'appel et je regarderai un peu ce qu'il me livre. Et je trouverai le bug bien avant toi qui aura choisi de te taper *tout* le code source livré, forcément, puisque pour prouver mathématiquement le code livré il te faut bien le lire.

Pour les erreurs vraiment stupide voire le sabotage je ne vois pas vraiment ce que tu veux montrer ... Mais il est vrai que c'est mieux je crois si c'est la même personne qui écrit un test et qui implémente la solution correspondante. Dans le cas du module dict pour erlang, le test s'adresse à un développeur. C'est donc normalement quelqu'un qui choisira la simplicité et qui implémentera un vrai dict plutôt que de hardcoder toutes les solutions du test manuellement. On parle d'un professionnel.

Bref dans mon exemple je fournissais un test en ayant connaissance de l'implémentation, je ne m'engagerai jamais sur du code que je n'ai pas fait (même si c'est moi qui ait écrit le test).

Citation :De plus tu ne réponds que sur les test du code pour le débug, qu'as tu as dire pour le reste, ne penses-tu pas que ce sont déjà des éléments suffisants pour tester le TDD ?

Enfin concernant le post de Ter Rowan, tu ne peux pas remplacer un stagiaire sur 3 ans par un ingénieur sur 3 mois. Ils ne font pas le même boulot. Ce n'est pas qu'une histoire de coûts. Ton ingé en a marre de reprendre du code au bout de deux semaines mais toi tu as besoin d'une personne pendant 3 ans pour faire certains travaux. Tu ne sais pas quels contrats tu aura dans un an, tu ne peux donc pas filer ce boulot à ton ingé. En contrepartie, même si tu as tout le temps nécessaire pour un projet, tu ne vais pas confier de prouver la correctidudition du code à un stagiaire dont ce n'est clairement pas le boulot. Tu peux tout au plus lui demander d'essayer de la prouver et de trouver les erreurs flagrantes mais tu aura besoin d'une compétence au dessus pour avoir confiance en ton code. Donc tu as besoin de l'ingé, et c'est clairement beaucoup plus cher, je suis d'accord avec son post. Des tests bien sentis et un peu de débug comme d'habitude font généralement de très bons résultats quand c'est fait par des bons.