26-08-2013, 11:55 AM
Bonjour à tous,
creusant encore un peu les "bonnes pratiques" pour la POO, j'en viens à me poser la question de la véritable utilité des tests unitaires. Même après recherche (sur jeuweb et sur google), je ne suis pas convaincu de leur utilité, et même le contraire: je les trouve quasiment malsains.Présentés comme ils le sont, je ne vois pas en quoi ils sont légitimes pour dire "ma classe fait bien ce qu'on attend d'elle": je trouve que la valeur de ces tests est nulle.
A mon sens, l'informatique doit être approchée comme des maths, et non comme du réel. Ok, dans l'industrie réelle, si on veut tester la fiabilité d'une chaîne de production ou d'un poste de travail, on échantillonne le poste en question en prenant un produit (une voiture par exemple), et en le testant. S'il marche, on considère que ok, tous les produits devraient marcher.
Cette approche me semble assez similaire au test unitaire:
Cela ressemble vachement à de l'échantillonnage. Or l'informatique n'est pas le réel: ce sont des maths. Faire du test type "échantillonnage" pour valider une classe, c'est comme dire "sin(0) = 0 et sin(1) = 0.84 donc sin(x) >= 0 pour tout x".
Je ne comprends donc pas pourquoi il est légitime de se reposer sur le résultat de tests unitaires pour justifier qu'une fonction marche. Par exemple, si ma fonction doit calculer x², je peux faire:
J'ai donc écris mon code de test, et il foire (la fonction square() n'existe pas encore). Je crée la fonction:
Elle passe le test unitaire sans soucis. Pourtant, elle est loin de calculer le carré du nombre passé en entrée (en serait-ce vraiment un en plus? sans typage, ce n'est pas certain) !
Le pire à mon sens, c'est qu'en se reposant sur les tests unitaires, il devient encore plus difficile de débuger le projet: on se dit que testSquare() passe, donc le bug ne vient pas de square().
En termes mathématiques, on ne démontre pas un théorème en disant "il marche pour telle et telle valeur", mais "il marche quelque soit la valeur qui respecte telles conditions": le nombre de tests à faire serait, en pratique, infini.
A la limite, le test unitaire devrait tester tous les entiers pris en charge par l'ordinateur (soit quand même 2^32)... Cela ne me semble franchement pas possible matériellement, question de puissance de calcul. Encore pire si le paramètre d'entrée de la fonction est une chaîne de caractères, ou une chaine binaire.
Alors, quel intérêt au test unitaire, si on ne peut pas se reposer dessus?
creusant encore un peu les "bonnes pratiques" pour la POO, j'en viens à me poser la question de la véritable utilité des tests unitaires. Même après recherche (sur jeuweb et sur google), je ne suis pas convaincu de leur utilité, et même le contraire: je les trouve quasiment malsains.Présentés comme ils le sont, je ne vois pas en quoi ils sont légitimes pour dire "ma classe fait bien ce qu'on attend d'elle": je trouve que la valeur de ces tests est nulle.
A mon sens, l'informatique doit être approchée comme des maths, et non comme du réel. Ok, dans l'industrie réelle, si on veut tester la fiabilité d'une chaîne de production ou d'un poste de travail, on échantillonne le poste en question en prenant un produit (une voiture par exemple), et en le testant. S'il marche, on considère que ok, tous les produits devraient marcher.
Cette approche me semble assez similaire au test unitaire:
25 assertEquals("Le total de la facture est mal calculé",
26 3 * 150 + 50, 0.0001,
27 maFacture.getTotal());
Cela ressemble vachement à de l'échantillonnage. Or l'informatique n'est pas le réel: ce sont des maths. Faire du test type "échantillonnage" pour valider une classe, c'est comme dire "sin(0) = 0 et sin(1) = 0.84 donc sin(x) >= 0 pour tout x".
Je ne comprends donc pas pourquoi il est légitime de se reposer sur le résultat de tests unitaires pour justifier qu'une fonction marche. Par exemple, si ma fonction doit calculer x², je peux faire:
function testSquare()
{
assertEquals("1² ne vaut pas 1!", square(1), 1);
assertEquals("(-1)² ne vaut pas 1!", square(-1), 1);
}
J'ai donc écris mon code de test, et il foire (la fonction square() n'existe pas encore). Je crée la fonction:
function square($x)
{
return 1;
}
Elle passe le test unitaire sans soucis. Pourtant, elle est loin de calculer le carré du nombre passé en entrée (en serait-ce vraiment un en plus? sans typage, ce n'est pas certain) !
Le pire à mon sens, c'est qu'en se reposant sur les tests unitaires, il devient encore plus difficile de débuger le projet: on se dit que testSquare() passe, donc le bug ne vient pas de square().
En termes mathématiques, on ne démontre pas un théorème en disant "il marche pour telle et telle valeur", mais "il marche quelque soit la valeur qui respecte telles conditions": le nombre de tests à faire serait, en pratique, infini.
A la limite, le test unitaire devrait tester tous les entiers pris en charge par l'ordinateur (soit quand même 2^32)... Cela ne me semble franchement pas possible matériellement, question de puissance de calcul. Encore pire si le paramètre d'entrée de la fonction est une chaîne de caractères, ou une chaine binaire.
Alors, quel intérêt au test unitaire, si on ne peut pas se reposer dessus?