IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Influence des tests sur le design du code


Sujet :

C++

  1. #1
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut Influence des tests sur le design du code
    Bonjour.

    Je travaille actuellement sur un projet et comme dans tout projet on ecrit des tests. Sauf que ces tests ont une influence sur le design du code.
    Typiquement, si j'ai un truc dans ce style
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    struct A{void foo();};
     
    struct B {
     B(A& aa): a(aa){}
     A& a;
    }'
    Pour tester unitairement B, je me retrouver a ecrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    struct ABase 
    {
     virtual void foo()=0;
    };
     
    //----VRAI CODE------
    struct A : publicABase {
     virtual void foo();
    };
     
    struct B {
     B(ABase& aa): a(aa){}
     ABase& a;
    };
    et le code de test suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    //----TEST CODE------
    struct FakeA : publicABase {
     virtual void foo(){/*dummy*/}
    };
    TEST(TESTB)
    {
    FakeA a;
    B b(a);
    //tests
    }
    Donc au final, on se retrouve des classes de bases remplies de fonctions virtuelles de partout (Java-like) alors qu'a la base, bah y'en avait pas.

    Et ca me dérange que le design du code soit impacte par les tests. Pour moi ce sont des choses orthogonales. On devrait tester notre code, pas modifier le code pour écrire des tests.

    Pouvez vous éclairer ma lanterne ? Qu'est ce que je loupe ?

    Merci !
    David.

    PS : Si ca vous intéresse, le framework de test c'est Google Test.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  2. #2
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Salut !

    Citation Envoyé par Davidbrcz Voir le message
    Et ca me dérange que le design du code soit impacte par les tests. Pour moi ce sont des choses orthogonales. On devrait tester notre code, pas modifier le code pour écrire des tests.
    Tu as parfaitement raison ! Le framework de tests que tu as choisi ne change pas grand chose au problème. Je pense que tu viens de toucher un point où tu as besoin de mock objects. Le principe est de générer des classes qui ont la même interface que les classes réelles mais qui derrière ont un comportement prévisible et vérifiable par le framework. Le cas précis que tu nous montres, à savoir l'ajout de virtualité pour pouvoir tester, est notamment traité, par le framework GoogleMock par exemple.
    Find me on github

  3. #3
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Je ne connais pas google test, donc je ne sais pas si c’est spécifique au framework. Néanmoins, je pense comme toi, que les tests n’ont pas à influer (sauf à la marge) sur l’implémentation. J’ai un peu le même problème avec des comportements privés que j’aimerai tester unitairement, ce qui est impossible sans les rendre publics, ce qui me dérange. Ce qui me dérange encore plus dans cette approche et que ça fait grossir le code des tests, qui n’a pas de raisons d’être exempt de bugs, d’autant que lui n’est pas testé, et qu’un bug dans un test peut masquer un vrai problème.

    Du coup, dans ton cas (bien sûr, c’est difficile de juger sur un exemple réduit au minimum), je vois difficilement l’intérêt de tester B sans A. Le tester avec un pseudo-A est à mon avis un remède pire :
    - de toute façon, tu testes A unitairement, donc tu peux valider les problèmes à son niveau
    - tu as besoin d’un A pour tester B. Si tu introduis un pseudo-A, tu introduis peut-être un bug qui donnera des faux négatifs, ou, pire, passera sous silence des échecs.
    - tu dois de toute manière tester A et B ensemble puisque c’est comme ça que c’est utilisé au final.
    - si tes contrats sont bien définis, tu sauras très rapidement, en cas de problème, s’il vient de A ou de B.

    Au final, tu fais plus de choses (donc tu augmentes les chances de mal les faire), pour un résultat bien maigre. D’autant que ce qui est le plus important de tester (je n’aime pas le terme unitaire, je préfère parler de test automatisé), dans une conception orientée « services », ce sont bien les services en eux-mêmes. Qui ont des chances d’être le résultat de la « collaboration » de plusieurs classes.

    Cela dit, si tu as vraiment besoin de faire ça (tester B avec un autre A), est-ce qu’utiliser des templates ne serait pas une meilleure solution ? À priori, tu as seulement besoin de polymorphisme statique, pas dynamique.

  4. #4
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    Personnellement j'utilise peu les mock objects mais je sais que c'est une approche qui est massivement répandue et qui a fait ses preuves. Introduire un pseudo-A n'est pas un "remède pire", c'est justement fait pour pouvoir découpler le test de l'implémentation de B et le test de l'implémentation de A. Si tu pètes A en injectant un bug, ce n'est pas pour ça que B est lui buggé et ses tests unitaires n'ont pas à casser. Les tests fonctionnels eux, doivent casser dans ce cas, oui. Les tests unitaires ne doivent pas être les seuls tests.

    Un pseudo-A n'est pas censé implémenter un comportement mais renvoyer toujours la même chose pour simuler le comportement attendu d'un autre objet. Par exemple, si tu as une méthode "calcul()" qui renvoie un int et fait des choses compliquées, tu vas mettre dans ton mock un "return EntierConstant;". Si tu parviens à introduire des bugs de cette manière, ça veut dire que les tests sont mal écrits, et ça peut toujours arriver, mock objects ou pas.

    Ensuite, tu crées plein de petits pseudo-A, un pour chaque use-case.

    Citation Envoyé par white_tentacle Voir le message
    Cela dit, si tu as vraiment besoin de faire ça (tester B avec un autre A), est-ce qu’utiliser des templates ne serait pas une meilleure solution ? À priori, tu as seulement besoin de polymorphisme statique, pas dynamique.
    C'est exactement l'approche proposée par le GoogleMock pour ce cas.
    Find me on github

  5. #5
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par jblecanard Voir le message
    Personnellement j'utilise peu les mock objects mais je sais que c'est une approche qui est massivement répandue et qui a fait ses preuves. Introduire un pseudo-A n'est pas un "remède pire", c'est justement fait pour pouvoir découpler le test de l'implémentation de B et le test de l'implémentation de A. Si tu pètes A en injectant un bug, ce n'est pas pour ça que B est lui buggé et ses tests unitaires n'ont pas à casser.
    Si A est pété, les tests unitaires de A ne passent pas (et comme je le sais, je teste A avant B ). Je ne me suis jamais retrouvé dans une situation où il était critique de continuer à tester B alors que A est pété. Je peux comprendre que ça existe sur de très gros projets, cela dit. Néanmoins, je vois plus les mock objects comme un moyen de forcer des cas improbables ou merdiques à tester (par exemple, rupture de connexion au milieu du traitement) que comme un moyen de continuer à tester un truc qui dépend d’un autre qui serait cassé.

    Un pseudo-A n'est pas censé implémenter un comportement mais renvoyer toujours la même chose pour simuler le comportement attendu d'un autre objet. Par exemple, si tu as une méthode "calcul()" qui renvoie un int et fait des choses compliquées, tu vas mettre dans ton mock un "return EntierConstant;". Si tu parviens à introduire des bugs de cette manière, ça veut dire que les tests sont mal écrits, et ça peut toujours arriver, mock objects ou pas.
    Oui. Mon soucis est que la quantité de bugs est toujours proportionnelle à la taille du code, et que :
    - le code des tests n’est pas lui-même testé
    - il ne fait pas l’objet de beaucoup d’attention en général

    Du coup, j’ai naturellement tendance à vouloir limiter sa taille.

  6. #6
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Citation Envoyé par jblecanard Voir le message
    Tu as parfaitement raison ! Le framework de tests que tu as choisi ne change pas grand chose au problème. Je pense que tu viens de toucher un point où tu as besoin de mock objects. Le principe est de générer des classes qui ont la même interface que les classes réelles mais qui derrière ont un comportement prévisible et vérifiable par le framework. Le cas précis que tu nous montres, à savoir l'ajout de virtualité pour pouvoir tester, est notamment traité, par le framework GoogleMock par exemple.
    J'avais vu les mock objets. Mais au final ca change pas grand chose. Soit faut mettre des fonctions virtuelles, soit faut mettre des templates partout, ou un mélange des deux. Dans tout les cas, faut modifier le code pour le tester =(
    Mais je trouve que ca n'offre pas assez de flexibilité.

    white_tentacle >> J'ai mis un exemple simplifie a l’extrême, mais en pratique je peux découpler assez fortement A et B au point que des test indépendants soient logiques.

    Ce qui me dérange encore plus dans cette approche et que ça fait grossir le code des tests, qui n’a pas de raisons d’être exempt de bugs, d’autant que lui n’est pas testé, et qu’un bug dans un test peut masquer un vrai problème.
    Tout a fait d'accord.

    Sinon pas trop de template, car ca casse la navigation de code de l'IDE () alors que ca marche avec des fonctions virtuelles et qu'on a pas de problématique de performance sur le temps CPU.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  7. #7
    Membre expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Points : 3 156
    Points
    3 156
    Par défaut
    A vrai dire, je trouve aussi que les mock font beaucoup de code à écrire, mais vu que plein de projets s'en servent, peut-être que ça aurait pu te convenir.

    Citation Envoyé par Davidbrcz Voir le message
    Sinon pas trop de template, car ca casse la navigation de code de l'IDE () alors que ca marche avec des fonctions virtuelles et qu'on a pas de problématique de performance sur le temps CPU.
    1) Je n'ai pas de problèmes sous vim
    2) Heu ? Les templates sont résolus à la compilation donc justement il n'y pas de surcoût runtime ? Même si dans la pratique le surcoût des fonctions virtuelles est assez faible (en tout cas, ce n'est généralement pas ma raison de les éviter).

    Citation Envoyé par white_tentacle
    Ce qui me dérange encore plus dans cette approche et que ça fait grossir le code des tests, qui n’a pas de raisons d’être exempt de bugs, d’autant que lui n’est pas testé, et qu’un bug dans un test peut masquer un vrai problème.
    Hélas ! Dans les grosses bases de code, on n'a pas vraiment le choix ! Pour ma part, je m'efforce de découpler les objets dans le design de base, non pas dans le but des les tester, mais au final ça simplifie les tests naturellement. J'écris beaucoup de tests fonctionnels riches avec des conditions aux bords au possible, et je passe un coup de valgrind et de gcov dessus pour voir si j'ai pas laissé passé un morceau.
    Find me on github

Discussions similaires

  1. Créer des reperes sur les lignes de code
    Par alafu dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 11/07/2007, 14h44
  2. besoin des tests sur futur site annuaire artistique
    Par mussara dans le forum Mon site
    Réponses: 8
    Dernier message: 27/04/2007, 18h19
  3. des information sur la programmation de codes barre
    Par mohammeedd1 dans le forum Windows
    Réponses: 2
    Dernier message: 16/01/2007, 15h14
  4. Récupérer le code des form sur Qt designer
    Par Death83 dans le forum Qt
    Réponses: 2
    Dernier message: 09/10/2005, 23h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo