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

Langage Java Discussion :

JUnit : tester une classe (dont le fichier source est) générée


Sujet :

Langage Java

  1. #1
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut JUnit : tester une classe (dont le fichier source est) générée
    Bonjour,

    J'ai un mécanisme de génération de classes (qui génère des fichiers source), et j'écris des tests unitaires sur ces classes générées :
    - La méthode main() de la classe Generation génère un fichier source A.java
    - J'ai une classe TestA de tests unitaires sur la classe A, qui a donc besoin de l'importer.

    Mon but est que JUnit génère tout seul la classe A (en appelant Generation.main()) avant de lancer le moindre test.
    Le problème est que testA a besoin d'importer A, donc:
    - @BeforeClass ne marchera pas ici. Il faut que JUnit génère A avant de faire le moindre Compilation check sur testA.
    - Si j'utilise un dynamic ClassLoader dans testA, je dois réecrire tout le test avec de l'introspection, plutôt qu'avec les méthodes déclarées dans la classe A, ce que je voudrais éviter.

    Sauriez-vous comment faire ?

    Merci d'avance !

  2. #2
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Euh c'est ton test unitaire qui génère des sources? un peu bizarre ça...

    En général, c'est une procédure séparée, lancée avant les tests, qui génère les sources.

    En Maven par exemple, tu as la phase "generate-sources", exécutée bien avant les tests, qui produit des sources dans target/generated-sources. Ensuite, l'ensemble est compilé (sources+sources générées+tests), puis les tests sont exécutés.

    Il faut bien dissocier 1) générer des sources puis 2) compiler puis 3) lancer les tests.

    PS: Maven vaut vraiment la peine d'être étudié. Il découpe le cycle de vie d'un projet en phase distinctes et bien séparées, et tu n'aurais pas toutes ces questions à te poser si tu l'utilisais...
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  3. #3
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Merci Pill_S !

    J'utilise Maven, mais je me demandais si JUnit était assez grand pour traiter la question.
    Apparement pas, et effectivement Maven semble donner une réponse "propre".

  4. #4
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Ouais enfin c'est bizarre qu'un unit test test une classe générée. Que le unit test teste le générator oui, mais la classe générée, non. C'est du test bullshit.

  5. #5
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Hello tchize_,
    C'est du test bullshit
    Je ne sus pas sur de comprendre pourquoi. Si le generateur ou le code générant évolue, tu peux vouloir tester que l'intégration de la classe générée se passe toujours bien.

  6. #6
    Membre expert

    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2004
    Messages
    2 301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Finance

    Informations forums :
    Inscription : Janvier 2004
    Messages : 2 301
    Points : 3 675
    Points
    3 675
    Par défaut
    Citation Envoyé par shaiHulud Voir le message
    Hello tchize_,

    Je ne sus pas sur de comprendre pourquoi. Si le generateur ou le code générant évolue, tu peux vouloir tester que l'intégration de la classe générée se passe toujours bien.
    Assez d'accord personnellement, mais je pense que ce que tchize_ veut dire, c'est qu'on ne test pas *directement* les objets générés. On teste les classes qui les utilisent (et du coup on couvre aussi les classes générées). De toute façon, souvent, 1) le code généré est trop simple pour mériter des tests personnalisés (c'est souvent que des beans, des adapters, etc.) et 2) on fait confiance au générateur
    "Le plug gros problème des citations trouvées sur internet, c'est qu'on ne peut jamais garantir leur authenticité"

    Confucius, 448 av. J-C

  7. #7
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par shaiHulud Voir le message
    Hello tchize_,

    Je ne sus pas sur de comprendre pourquoi. Si le generateur ou le code générant évolue, tu peux vouloir tester que l'intégration de la classe générée se passe toujours bien.
    Tu as trois choses à tester:

    • un test d'intégration: étant plus loin que les unit test dans la chaine, normalement ta classe a été générée depuis longtemps ET c'est c'est l'ensemble de l'appli que tu teste pas ses composants. Pour ça, le unit test n'a même pas à savoir que la classe est générée. Je pourrais la créer à la main, la maintenir à la main ou la faire disparaitre, le unit test reste le même
    • un test sur le générateur même: le générateur étant un outil à part, ça fait l'objet idéalement d'un projet séparé où le générateur est testé. Il n'y a pas de référence explicite aux classe générées, juste des références indirectes: "je prend la sortie du du GeneratorA et je regarder que cette sortie correspond à certains critères". Comme par exemple: est-ce qu'elle dispose d'une méthode X, est-ce qu'elle compile, etc.
    • un test unitaire sur le code qui utilise le code généré: on lui substitue un mock puisqu'on teste l'appelant et pas la classe générée.


    aucun de ces cas ne nécessite que tu génère la la fois la classe depuis le test et que tu dispose du byte code généré à la compilation du test unitaire

  8. #8
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Merci beaucoup pour ces explications !

    J'ai quand même l'impression de passer à coté de certaines possibilités avec ces 3 seuls cas. Comment faire pour ces 2 exemples:

    1) Je génère une méthode compareTo() pour des classes contenant des arrays. L'ordre implémenté est d'abord par longueur des arrays, et par ordre lexicographique en cas d'égalité. Il s'avère que le générateur de code avait une erreur (il inversait les conditions "a.length == b.length" et "b.length != a.length", si bien que la méthode état complètement fausse). Puisque c'est le générateur qui est en cause, j'imagine etre dans le second cas décrit par Tchize_, mais comment puis-je détecter cette erreur avec des références indirectes au code généré ? J'ai l'impresion de m'orienter vers des tests avec reflection.

    2) Je fais évoluer le code générant une classe (pas le générateur), disons en modifiant le type d'un attribut, ou en en rajoutant. Comment vérifier que l'objet reste serializable, ou que ses méthodes hashcode/equals ne violent pas le "hashmap contract" ? Il me semble que le test du client de ma classe généré pourrait très bien passer à côté du problème.

  9. #9
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par shaiHulud Voir le message
    mais comment puis-je détecter cette erreur avec des références indirectes au code généré ? J'ai l'impresion de m'orienter vers des tests avec reflection.
    Ton test ressemblerait à ça:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    generateur.generate(parametres);
    assertFileExist("machin.java");
    callCompiler("machin.java");
    assertFileExist("machin.class");
    ClassLoader cl = new URLClassLoader(new URL[] {cheminDeCompilation});
    Class<?> clazz = cl.loadClass("machin");
    // on peux ici tester éventuellement l'existence de certains constructeur ou propriété attendues
    Object instance1 = clazz.newInstance();
    Object instance2 = clazz.newInstance();
    // on manipule instance 1 et 2
    assertEquals(instance1, instance2);

    ainsi tu teste que les classes générées par ton générateur on bien un comportement attendu.

  10. #10
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Ok, c'est ce que je cherchais à éviter. Mais tu as raison, c'est le seul moyen de tester proprement le générateur en toute généralité.
    Merci beaucoup !

  11. #11
    Membre éprouvé
    Inscrit en
    Août 2010
    Messages
    1 124
    Détails du profil
    Informations forums :
    Inscription : Août 2010
    Messages : 1 124
    Points : 1 277
    Points
    1 277
    Par défaut
    Mais si les UT sont écrits avec de la reflection, ca devient facile de générer la classe dans le test unitaire et d'utiliser un dynamic class loader.
    Du coup je ne vois plus de raison de ne pas tester la classe générée elle même. D'ailleurs c'est ce que tu fais.

  12. #12
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Non, je teste "une" classe générée, qui n'est pas nécessairement celle que tu utilisera dans ton code. Ton générateur dois générer pas mal de comportements, je suppose, et chaque comportement doit être testé. Ces comportements dépendent de paramètres vraissemblablement donc chaque combinaison de paramètre doit être couverte. Donc ce seront donc des dizaines de versions différentes de la classe que tu génèrera pour tester les différents cas de figures possible.

    De plus tu peux limiter au maximum la reflection en ayant la classe générée implémentant une interface connue à l'avance, si c'est possible.

    Ta compilation finale, elle, ne gérera qu'un seul cas de figure.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 9
    Dernier message: 13/03/2015, 18h19
  2. [AC-2007] Modifier une liste dont l'origine source est une Table/Requête
    Par Cinesra dans le forum VBA Access
    Réponses: 6
    Dernier message: 09/11/2010, 14h20
  3. Sauvegarder/Lire une classe dans un fichier
    Par Rodrigue dans le forum C++
    Réponses: 10
    Dernier message: 10/09/2005, 14h12
  4. Réponses: 4
    Dernier message: 10/02/2005, 16h10
  5. [C#] [.NET] Lecture d'une classe dans un fichier
    Par niPrM dans le forum Windows Forms
    Réponses: 4
    Dernier message: 18/05/2004, 08h57

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