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

Tests et Performance Java Discussion :

utilisation des mock dans les test unitaires. [EasyMock]


Sujet :

Tests et Performance Java

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 10
    Points : 7
    Points
    7
    Par défaut utilisation des mock dans les test unitaires.
    Bonjour à tous, je suis nouveau sur ce forum.

    Je tente d'intégrer des testes unitaires dans un projet. (chose que j'avais toujours bâclé jusqu'ici).

    Pour tenter de bien les gérer cette fois-ci, je me suis intéressé à l'utilisation de mock objets (easyMock pour le moment mais après une visite de l'une de vos discussions, je compte essayer mockito).

    Mon problème se situe plus au niveau pattern d'utilisation des mock objets que niveau implementation :

    Pour faire simple, j'ai une structure de graph (graph, noeuds et arcs) et un arc contient 2 noeuds, le noeud source et le noeud cible.

    Pour l'arc je pense avoir compris comment faire :

    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    public class ArcImple implements IArc {
     
       private INode source;
       private INode cible;
     
       public ArcImpl(INode source, INode sink) {
         ....
        }
     
    }
     
    public class ArcTest {
     
        private IMocksControl  control;
        private IArc               arcToTest;
        private INode            sourceMock;
        private INode            sinkMock;
     
        @before
        public void setUp() {
            this.sourceMock = this.control.createMock(INode.class);
            this.sinkMock = this.control.createMock(INode.class);
            this.arcToTest = Factory.createArc(this.sinkMock, this.arcToTest)
        }  
     
        // puis les méthodes à tester
    }

    Voila pour cette classe, je ne detail pas ces testes car je pense les avoir bien réussis. Mon problème se pose pour la classe Graph. Voici à quoi elle ressemble (je simplifie en oubliant dans cet exemple les arcs):

    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
    16
    17
    18
    19
    20
     
     
    public interface IGraph {
     
       void addNode(INode node);
    } 
     
    public class Graph implements IGraph {
     
        private Set<INode> nodes;
     
        public Graph() {
           nodes = new hastSet<INode>();
        }
     
        public void AddNode(INode node) {
            nodes.addNode(node);
            // traitements supplémentaires    
        }
    }

    Voila, mon probleme se pose pour tester la methot addNode(INode node) de IGraph, en particulier, je voudrai savoir si elle utilise bien la methode "add()" de l'interface "Set".

    Mais cette collection est totalement encapsulé dans Graph, il y a ni getter ni setter dessus. donc je ne peux faire ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Set<Inode> nodesMock = this.control.createMock(Set.class)
    this.graphToTest.setNodes(nodesMock);
    Voila, j'espère que mon post n'est pas trop long et que j'ai pu bien faire comprendre mon petit soucis.

    Cordialement,

    Jérémie

  2. #2
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Points : 595
    Points
    595
    Par défaut
    Salut,

    Oui, à choisir : 100 fois plus Mockito qui est plus intuitif et puissant.
    Pour ton prob, t'as différentes solutions.
    Pour simplifier et parce qu'il est tard, je te dirais que si tu ne peux pas mocker un champ interne de ta classe à tester car tu ne veux pas casser l'encapsulation ou les routines internes, ne mocke pas ce champ (ton set).
    Tu n'es pas obligé de tout mocker.
    Il faut toujours se poser la question de l'intérêt ou non de mocker.
    Pour tester ta méthode AddNode(), je te proposerais plutôt de tester en vérifiant l'état de ton set à l'issue de l'exécution de la méthode. Dans ta classe, tu n'offre pas d' accès publique à ce set de façon directe (getSet()) ou indirecte (via des itérateurs ou des wrappers).
    Si les besoins de cette ta classe doivent t'amener à d'offrir un tel accès, utilise cet accès pour tester ta méthode AddNode().
    Si ce n'est pas le cas, tu n'es pas obligé de casser l'encapsulation de ton code applicatif, par exemple ajouter un getter.
    Beaucoup de gens choisissent cette possibilité.
    Mais le problème est que l'on créé du code utilisé uniquement pour le test u.
    Parfois, c'est pas grave (un constructeur par exemple). D'autre fois, ca le devient plus. Par exemple ici un getter sur le Set.
    Perso, je préfère utiliser des méthodes peu orthodoxes dans les tests pour garder un code source propre. Par exemple, la méthode de ton test u pourrait user de la réflexion pour récupérer ton objet set si tu ne veux absolument pas offrir un accès public à ton set.

    A++
    Ils flottent tous en bas

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 10
    Points : 7
    Points
    7
    Par défaut
    merci thebloodyman pour ta réponse,

    donc, j'ai essayer d'utiliser la transitivité de java de cette façon :

    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    	ISimpleEdge edgeMock = this.control.createMock(ISimpleEdge.class);
    		try {
    			Set<ISimpleNode> graphEdges = new HashSet<ISimpleNode>();
    			System.out.println("class = " + graphToTest.getClass());
    			Class<? extends ISimpleGraph> class1 = graphToTest.getClass();
    			Field[] fields = graphToTest.getClass().getDeclaredFields();
    			Method[] methods = graphToTest.getClass().getMethods();
    			((SimpleGraphImpl)graphToTest).getClass().getDeclaredField("edges").get(graphEdges);
    			System.out.println("edges = " + graphEdges);
    		} catch (IllegalArgumentException e) {
    			System.err.println(e);
    			e.printStackTrace();
    		} catch (SecurityException e) {
    			System.err.println(e);
    			e.printStackTrace();
    		} catch (	ISimpleEdge edgeMock = this.control.createMock(ISimpleEdge.class);
    		try {
    			Set<ISimpleNode> graphEdges = new HashSet<ISimpleNode>();
    			System.out.println("class = " + graphToTest.getClass());
    			Class<? extends ISimpleGraph> class1 = graphToTest.getClass();
    			Field[] fields = graphToTest.getClass().getDeclaredFields();
    			Method[] methods = graphToTest.getClass().getMethods();
    			((SimpleGraphImpl)graphToTest).getClass().getDeclaredField("edges").get(graphEdges);
    			System.out.println("nodes = " + graphEdges);
    		} catch (IllegalArgumentException e) {
    			System.err.println(e);
    			e.printStackTrace();
    		} catch (SecurityException e) {
    			System.err.println(e);
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			System.err.println(e);
    			e.printStackTrace();
    		} catch (NoSuchFieldException e) {
    			System.err.println(e);
    			e.printStackTrace();
    		} e) {
    			System.err.println(e);
    			e.printStackTrace();
    		} catch (NoSuchFieldException e) {
    			System.err.println(e);
    			e.printStackTrace();
    		}
     
    ...
     
    }
    seulement, ça me lance une IllegalAccessException car l'attributs nodes est privé. ET je comprend bien cela, en effet je trouvais que si on pouvais acceder a toutes les information de la classe de cette façon (meme aux informations privées) dangereuse. Donc on dirai que je n'ai pas d'autre choix que de tenter de faire un getter (getNodes() ) on dirait. c'est dommage. Si une personne voit une autre solution, n'hésitez pas. Pour cette classe là, créer la methode getNodes, ne me dérange pas, mais j'en ai une autre ou ça va me déranger.

    Sinon, je vais tester mockito .

    jérémie

  4. #4
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Points : 595
    Points
    595
    Par défaut
    seulement, ça me lance une IllegalAccessException car l'attributs nodes est privé. ET je comprend bien cela, en effet je trouvais que si on pouvais acceder a toutes les information de la classe de cette façon (meme aux informations privées) dangereuse
    C'est normal, mais comme je te le rappelle, on réalise cela dans le contexte d'un test unitaire.
    Donc le danger ne se propage pas ds l'appli

    Pour désactiver la sécurité des méthodes/champs privé, tu dois appliquer la méthode setAccessible(true) sur la méthode/champ privé avant de pouvoir l'utiliser.

    Ton code de test m'a l'air un peu trop complexe. Tu devrais propager toutes les exceptions liées à la relfexion. Si il y a une exception, tu auras une erreur de test et c'est ce que tu veux.
    Ensuite dans ton cas, tu n'a besoin que de récupérer le set.
    Tu peux faire ca simplement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    ArcImple  underTest = new ArcImple();
    //action
    underTest.AddNode(new Node());
    //assertion
    Field nodesField = graphToTest.getClass().getDeclaredField("nodes") ;
    nodesField.setAccessible(true);
    Set<INode> actualSet = (Set<INode>) nodesField.get(underTest);
    // tu fais tes assertions junit/testng ici
    Ils flottent tous en bas

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 10
    Points : 7
    Points
    7
    Par défaut
    yeah ça mache bien .
    merci beaucoup

    Mais je me pose une question, s'il suffit d'utiliser la methode "setAccessible(true);" pour retrouver les éléments privée d'une classe, un utilisateur ayant de mauvaises intention ne pourrait pas s'en servir? cela ne constitue pas un problème de sécurité?

    Bon je me lance pour mockito.

    Jérémie

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Points : 595
    Points
    595
    Par défaut
    yeah ça mache bien .
    merci beaucoup


    Pour la question de sécurité, c'est sûr. On peut parfois détourner complétement la fonction des objets.
    Apres, si on peut ou non désactiver l'option, j'en sais rien !
    Ou est Tchize ?

    mauvaises intention
    Il faudrait que ton objet cache des trésors non accessibles par son api publique

    Pour le développeur client de la classe, le risque que je vois à récupérer les organes internes des classes, c'est de faire un code dépendant de ses mécanismes internes.
    Le jour ou ou la classe décide de changer sa mécanique interne, cela peut impacter fortement le code client.
    Pour le cas du test, c'est le cas aussi. Mais le seul impact sera la méthode de ta classe qui teste la fonction, pas les autres méthodes ou le reste de ton code, sinon il y a aussi un prob.
    Ils flottent tous en bas

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 10
    Points : 7
    Points
    7
    Par défaut
    merci pour ta réponse.

    Je reste étonné que sun a mis cette fonctionnalité dans java. Mais j'avoue que dans mon cas, ça m'est bien utile.
    Sinon j'ai bien réussis à faires mes testes unitaire avec mockito .
    Le passage de easyMock à mockito n'est pas trop difficile.
    de plus l'annotation @Mock est pratique.


    Bonne continuation en tous cas.
    Maintenant je me consacre à maven et google guice

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    476
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 476
    Points : 595
    Points
    595
    Par défaut
    Oui pas mal du tout la petite annotation + initMocks()

    google guice ? original ! Jamais encore testé

    Bonne continuation à toi aussi
    Peut etre @+ tard sur le forum
    Ils flottent tous en bas

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

Discussions similaires

  1. Utilisation des collections dans les UserControl
    Par flo67 dans le forum Windows Forms
    Réponses: 2
    Dernier message: 18/01/2008, 20h34
  2. Utiliser des Filler dans les structures avec ACCEPT
    Par beegees dans le forum Cobol
    Réponses: 2
    Dernier message: 13/01/2008, 19h09
  3. Utiliser des variables dans les noms d'objet
    Par Torkan dans le forum VB 6 et antérieur
    Réponses: 6
    Dernier message: 15/03/2007, 23h54
  4. utilisation des sessions dans les jsp
    Par casho dans le forum Servlets/JSP
    Réponses: 1
    Dernier message: 16/08/2006, 19h45

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