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).
Pour la démonstration:
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):
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 ).
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.
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
Pour la démonstration:
Citation :E l'élément "parfait": il fait exactement ce qu'on veut quelque soit l'entréeOui, 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...).
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.
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 ).
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.