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 :

Java, Jhipster & tests unitaires (back end/office)


Sujet :

Tests et Performance Java

  1. #41
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 523
    Points : 147
    Points
    147
    Par défaut
    Ok.


    Mais tout ça m'évoque, du coup, deux autres points:

    1.)
    - j'ai fini par ramener dans la classe de test les 2 String
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    String urlEnveloppe = "https://almdtsi.itn.ftgroup/qcbin/rest/domains/dom_g/projects/greenwich_dev";
    String folderReleaseCible = urlEnveloppe+"/"+ Models.RELEASEFOLDER+"s/134";
    à passer en paramètre à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    verify(mockCCBRepos).readWithURL(new ObjectRequest().setURLEntity(folderReleaseCible));
    pour essayer de comprendre ce que me voulait intelliJ

    - je voulais donc passer exactement la même chose dans la classe de base que dans la classe de test
    (et on sait maintenant pourquoi ça ne marchait quand même pas! )

    Or, à mon sens, d'après ce que j'ai justement appris de toutes mes recherches, c'est qu'une méthode de test ne doit pas tester les attributs d'une méthode, mais le bon fonctionnement de cette méthode, peu importe la valeur des attributs envoyés!

    C'est à dire qu'à la limite on aurait même pu faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    verify(mockCCBRepos).readWithURL(new ObjectRequest().setURLEntity("toto"));
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    verify(mockCCBRepos).readWithURL(toto = new ObjectRequest());
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    verify(mockCCBRepos).readWithURL(1 ObjectRequest mocké);
    En gros envoyer n'importe quoi, du moment que le type du paramètre soit le bon!


    Mais du coup, on se heurterait de nouveau aux problèmes d'instances différentes, dans ce cas là, non?
    Là, j'ai encore un flou...


    2.) quand tu dis
    Or ce n'est pas le même, puisque tu l'as explictement instancié une deuxième fois (il y a 2x l'invocation "new ObjectRequest" dans le code).
    -> tu veux parler des 2 invocations (GIVEN + THEN), dans le code de la méthode de test?
    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
    	@Test
        public void test_templateSearch() throws Exception {
        // GIVEN: quand la situation est comme ceci
        // (on configure le mock pour que lorsque l'on invoque readWithURL avec n'importe quel argument, il retourne 1 valeur cohérente)
        ResponseEntity entity = mock(ResponseEntity.class);
        when(entity.toString()).thenReturn("bidon");
        when(mockCCBRepos.readWithURL((ObjectRequest) any())).thenReturn(entity);
        CampagneCartouche or = new CampagneCartouche(); // TODO initialiser une valeur cohérente
    
    
        // WHEN: et que je fais cela
        instance.templateSearch(or);
    
    
        // THEN: je m'attend à ce qu'il se passe ceci (tester le code de la méthode)
        verify(mockCCBRepos).requestLoging("https://almdtsi.itn.ftgroup/qcbin/api/authentication/sign-in");
    
        String urlEnveloppe = "https://almdtsi.itn.ftgroup/qcbin/rest/domains/dom_g/projects/greenwich_dev";
        String folderReleaseCible = urlEnveloppe+"/"+ Models.RELEASEFOLDER+"s/134";
        verify(mockCCBRepos).readWithURL(new ObjectRequest().setURLEntity(folderReleaseCible));
    
        verify(mockCCBRepos).requestLoging("https://almdtsi.itn.ftgroup/qcbin/api/authentication/sign-out");
    	}
    OU

    -> l'autre explication que je vois, étant que la classe de test est liée quelque part à la classe de base, et donc 1 invocation dans base + 1 invocation dans test = 2 invocations au total?

    Mais je ne sais pas si je suis clair?

  2. #42
    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
    1. On ne teste pas directement les paramètres (en fait, on les teste, mais dans des classes de test dédiées à chaque type de paramètres), mais on teste que chaque cas se présentant fait réagir l'implém correctement.

    Dans verify, on peut passer ce qu'on veut, soit une instance hard-codée et dans ce cas là mockito va utiliser equals, soit un critère plus complexe avec argThat:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    Mockito.verify(monmock).save(argThat(new CustomMatcher<MonObjet>("must have saved an " + MonObjet.class + " with the field pouet containing 3") {
                @Override
                public boolean matches(Object item) {
                    MonObjet o = (MonObjet) item;
     
                    return Objects.equals(3, o.getPouet());
                }
            }));
    Là, on vérifie que save a été invoqué avec en paramètre un MonObjet dont le champ pouet contenait 3. Equals n'entre plus en compte.

    2. Oui, ta deuxième réponse: je dis qu'il y a un "new ObjectRequest" dans l'implém (CreationCampagneBlocService) et un dans le test. Donc 2 instances. Qui n'overrident pas equals. Donc mockito dit "pas bon"
    "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. #43
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 523
    Points : 147
    Points
    147
    Par défaut
    Ok, merci.

    Je fais juste un petit flashabck: 16/02/2018 à 16h40
    à propos du mock de Entity

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    // GIVEN
    ResponseEntity entity = Mockito.mock(ResponseEntity.class);
    Mockito.when(entity.xxx()).thenReturn(...); // configurer la ResponseEntity en fonction de tes besoins (hint: tu as besoins de simuler des réponses représentant ce qui est habituellement renvoyé par le service rest, par exemple, un petite réponse, une grosse, une réponse d'erreur, pas de réponse du tout, etc...)
    Mockito.when(mockCCBR.readWithURL((ObjectRequest) any())).thenReturn(entity);
    peux-tu préciser ce que tu entends exactement par entity.xxx, entity étant une classe Jhipster, si je ne m'abuse?
    donc quelle méthode en particulier?

  4. #44
    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
    Classe JHipster ou pas, même combat.

    xxx correspond à toutes les méthodes qu'il faudra mocker pour tester un certain cas d'utilisation de l'implém sous test. ça pourrait ressembler à ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    ... blabla
    // par exemple, dans notre test, on doit vérifier comment réagit l'implém quand la réponse du service sous-jaçent est une erreur 400
    Mockito.when(entity.getStatusCode()).thenReturn(HttpStatusCode.BAD_REQUEST); // le statut sera 400
    Mockito.when(entity.getBody()).thenReturn("{\"reason\": \"blbabl\"}");  // le body sera... quelque chose
    // TODO : il faudra peut-être mocker d'autre élément de ResponseEntity, en fonction des besoins
     
    ... blabla
    // dans le when on fait l'appel
    // dans le then on vérifie que lorsque la réponse est 400 le comportement a été correct
    "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

  5. #45
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 523
    Points : 147
    Points
    147
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    //given
    // par exemple, dans notre test, on doit vérifier comment réagit l'implém quand la réponse du service sous-jaçent est une erreur 400
    Mockito.when(entity.getStatusCode()).thenReturn(HttpStatusCode.BAD_REQUEST); // le statut sera 400
    Mockito.when(entity.getBody()).thenReturn("{\"reason\": \"blbabl\"}");  // le body sera... quelque chose
    // dans le when on fait l'appel
    // dans le then on vérifie que lorsque la réponse est 400 le comportement a été correct
    Ok sur le principe oui, mais conceptuellement tu aurais un exemple concret sous la main?

    parce que:
    1.)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    //given
    when(mockResponseEntity.getStatusCode()).thenReturn(HttpStatus.BAD_REQUEST);
    //then
    assertEquals(mockResponseEntity.getStatusCode(), HttpStatus.BAD_REQUEST);
    n'a pas de sens, test forcément vrai *

    OU

    2.)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    //given
    when(mockResponseEntity.getStatusCode()).thenReturn(HttpStatus.BAD_REQUEST);
    //then
    assertEquals(mockResponseEntity.getStatusCode(), HttpStatus.TOUT_AUTRE_CODE_RETOUR);
    non plus, car test forcément faux *

    * puisqu'on sait qu'on aura bien BAD_REQUEST, vu que c'est ce qu'on a paramétré

  6. #46
    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 un exemple concret... pas vraiment... je croyais justement qu'on était sur un exemple concret (PS je t'ai proposé de commiter le code sur github pour s'y retrouver plus facilement et t'as pas voulu...)

    Si tu regardes bien, on ne fait jamais d'assert sur un mock, ça n'a effectivement pas de sens... Le mock est là uniquement pour simuler le comportement des sous-systèmes. Je te rappelle que la classe sous test est CreationCampagneBlocService, le ResponseEntity on le mock pour faire croire à CreationCampagneBlocService qu'il s'est pris une erreur 400.

    Par contre on fait des verify. Verify permet de s'assurer que l'implém sous test a bien invoqué quelque chose sur un de nos mocks
    "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. #47
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 523
    Points : 147
    Points
    147
    Par défaut
    1.)
    Euh un exemple concret... pas vraiment... je croyais justement qu'on était sur un exemple concret (PS je t'ai proposé de commiter le code sur github pour s'y retrouver plus facilement et t'as pas voulu...)
    c'est pas tant que je ne veuille pas, mais plutôt que je ne sache pas vraiment faire.
    de plus, diffuser au monde entier un code-source de mon client, pas sûr que ça plaise vraiment.
    (car vu les imbrications, à mon avis, poster seulement 3 ou 4 classes isolées... )


    2.)
    Si tu regardes bien, on ne fait jamais d'assert sur un mock, ça n'a effectivement pas de sens... Le mock est là uniquement pour simuler le comportement des sous-systèmes. Je te rappelle que la classe sous test est CreationCampagneBlocService, le ResponseEntity on le mock pour faire croire à CreationCampagneBlocService qu'il s'est pris une erreur 400.
    ok, pas d'assert sur un mock, ça c'est clair


    3.)
    Par contre on fait des verify. Verify permet de s'assurer que l'implém sous test a bien invoqué quelque chose sur un de nos mocks
    et voilà, nouveau paumé!
    dans ce cas qu'est-ce-que serait un bon exemple de verify sur le ResponseEntity mockResponseEntity?
    pour vérifier, comme tu dis, que lorsque la réponse est 400 le comportement a été correct?

    elle me gonfle cette mission, elle me gonfle!!
    j'ai l'impression d'être totalement débile, et ça m'énerve!!

  8. #48
    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
    Bon laisse tomber github, on va pas rajouter de la complexité maintenant. Mais pour info, tu crée un compte, tu créées un repo, tu installes git chez toi, tu clone le repo, tu ajoutes les sources, tu commit et push et après moi j'peux travailler sur tes sources

    Ah au fait j'ai jamais demandé les sources de ton client, je voulais plutôt que tu sortes un projet perso de ton historique, que tu connaisses bien et dont les sources soient libres... mais diffuser les sources du client tu te ferais virer illico et ce serait normal!!

    Sinon pour répondre. Le verify n'est pas un assert comme les autres. Tu l'utilises quand tu veux t'assurer qu'une action précédemment effectuée (le "when") a, par le truchement des méandres de la vie (comprendre: d'une façon qui importe peu ), produit l'appel voulu sur le mock. Et comme je l'avais déjà mentionné, c'est souvent pas les meilleures assertions qu'on puisse faire (ça vérifie des détails d'implémentation, ce qu'un bon test ne doit pas faire). Vois ça comme une couche de vérification supplémentaire. Mais la valeur ajoutée, c'est dans les Assert, pas dans les Verify.

    En l'occurence, il n'y a pas de "bons" Verify à utiliser sur ResponseEntity. Plutôt sur CreationCampagneBlocRepository, mais ResponseEntity est plutôt un Value Object relativement inerte, donc pas grand chose à tester dessus

    PS: non tu n'es pas débile, c'est complexe et fais intervenir beaucoup de notions. Bientôt ça te semblera facile
    "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

  9. #49
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 523
    Points : 147
    Points
    147
    Par défaut
    1.)
    Bon laisse tomber github, on va pas rajouter de la complexité maintenant. Mais pour info, tu crée un compte, tu créées un repo, tu installes git chez toi, tu clone le repo, tu ajoutes les sources, tu commit et push et après moi j'peux travailler sur tes sources

    Ah au fait j'ai jamais demandé les sources de ton client, je voulais plutôt que tu sortes un projet perso de ton historique, que tu connaisses bien et dont les sources soient libres... mais diffuser les sources du client tu te ferais virer illico et ce serait normal!!
    LE problème étant que je n'ai pas de projets perso à uploader malheureusement, d'une part, et que de l'autre j'ai besoin de comprendre sur le cas concret du projet qui m'occupe, là


    2.)
    Sinon pour répondre. Le verify n'est pas un assert comme les autres. Tu l'utilises quand tu veux t'assurer qu'une action précédemment effectuée (le "when") a, par le truchement des méandres de la vie (comprendre: d'une façon qui importe peu ), produit l'appel voulu sur le mock. Et comme je l'avais déjà mentionné, c'est souvent pas les meilleures assertions qu'on puisse faire (ça vérifie des détails d'implémentation, ce qu'un bon test ne doit pas faire). Vois ça comme une couche de vérification supplémentaire. Mais la valeur ajoutée, c'est dans les Assert, pas dans les Verify.
    donc en gros, dans ce cas là, la méthode de test se "limiterait" bien à ça?
    (méthode fortement commentée, pédagogie oblige)
    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
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
     
     @Test
        public void templateSearch() throws Exception {
     
        System.out.println("-> test unitaire de la méthode  <<< templateSearch() >>>\n");
     
        //*****************************************
        // GIVEN: quand la situation est comme ceci
        //*****************************************
            // (on configure le mock pour que lorsque l'on invoque readWithURL avec n'importe quel
            // argument, il retourne 1 valeur cohérente, càd 1 responseEntity = type de retour de readWithURL()
            // il faut donc déclarer un objet ResponseEntity
            ResponseEntity mockResponseEntity = mock(ResponseEntity.class);
            when(mockCCBRepos.readWithURL((ObjectRequest) any())).thenReturn(mockResponseEntity);
     
            // ResponseEntity étant un mock, on pourrait aussi configurer certaines de ses methodes si besoin
            // ie: vérifier comment réagit l'implém quand la réponse du service sous-jaçent est une erreur 400
            //when(mockResponseEntity.getStatusCode()).thenReturn(HttpStatus.BAD_REQUEST);
            //when(mockResponseEntity.getBody()).thenReturn("{\"reason\": \"blbabl\"}");
            //when(mockResponseEntity.hasBody()).thenReturn(true);
     
            //paramètre en INPUT de la méthode
            CampagneCartouche or = new CampagneCartouche();
     
     
        //**************************
        // WHEN: et que je fais cela
        //**************************
            instance.templateSearch(or);
     
     
        //**************************************************************************
        // THEN: je m'attend à ce qu'il se passe ceci (tester le code de la méthode)
        //**************************************************************************
     
            // vérifier l'appel des 3 méthodes de la classe de base
            // 1 LOGIN
            verify(mockCCBRepos).requestLoging("https://xxxxxxxxxxxxx/qcbin/api/authentication/sign-in");
     
            // 2 readWithURL
            /******
            Il y a 2 "new ObjectRequest" dans classe de base ET classe de test... donc 2 instances différentes, qui n'overrident pas equals.
            Donc mockito dit "pas bon": argument(s) are different!
            Il faut donc implémenter equals() et hashCode() dans la classe ObjectRequest
            ******/
            String urlEnveloppe = "https://xxxxxxxxxxxxx/qcbin/rest/domains/dom_g/projects/greenwich_dev";
            String folderReleaseCible = urlEnveloppe+"/"+ Models.RELEASEFOLDER+"s/134";
            verify(mockCCBRepos).readWithURL(new ObjectRequest().setURLEntity(folderReleaseCible));
     
            /*****
            Dans verify, on peut passer ce qu'on veut, soit une instance hard-codée et dans ce cas là mockito va utiliser equals, soit un critère plus complexe avec argThat:
     
            Mockito.verify(monmock).save(argThat(new CustomMatcher<MonObjet>("must have saved an " + MonObjet.class + " with the field pouet containing 3") {
            @Override
            public boolean matches(Object item) {
            MonObjet o = (MonObjet) item;
     
            return Objects.equals(3, o.getPouet());
            }
            }));
            *****/
     
            // 3 LOUGOUT
            verify(mockCCBRepos).requestLoging("https://xxxxxxxxxxxxx/qcbin/api/authentication/sign-out");
     
           // PLUS d'éventuels assert*() pertinents à faire
     
    }
    car je ne vois pas d'assert pertinent à faire .
    dans l'absolu, on aurait pu tester que folderReleaseCible not null, mais comme on l'a initialisé à la main juste avant l'appel à readWithURL(), ça pas de sens


    3.)
    PS: non tu n'es pas débile, c'est complexe et fais intervenir beaucoup de notions. Bientôt ça te semblera facile
    que l'univers (ou n'importe quoi d'autre) t'entende!!


    4.) merci pour ta patience d'ange!!

    c'que j'étais bien moi, pendant ma période suisse

  10. #50
    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 steph68b Voir le message
    1.)
    LE problème étant que je n'ai pas de projets perso à uploader malheureusement
    Arf c'est triste, bon bin tant pis.

    Citation Envoyé par steph68b Voir le message
    2.)
    donc en gros, dans ce cas là, la méthode de test se "limiterait" bien à ça?
    Oui. En général on commence avec des cas de tests simples (souvent flaggés "vanilla" pour "cas standards pas complexe"), et on augmente la complexité à chaque fois qu'un nouveau besoin business se présente. Ou à chaque fois qu'un incident apparait. A terme, si c'est bien fait, les tests sont une excellente documentation des différentes contraintes en place (largement meilleur que la javadoc ou un pdf qui traine dans un coin).

    Citation Envoyé par steph68b Voir le message
    car je ne vois pas d'assert pertinent à faire .
    dans l'absolu, on aurait pu tester que folderReleaseCible not null, mais comme on l'a initialisé à la main juste avant l'appel à readWithURL(), ça pas de sens
    Effectivement, c'est nul de tester ce qu'on initialise juste en dessus.

    Citation Envoyé par steph68b Voir le message
    3.)
    que l'univers (ou n'importe quoi d'autre) t'entende!!
    In nomine patter et fili et spiritus sancti.... Amen!

    Citation Envoyé par steph68b Voir le message
    4.) merci pour ta patience d'ange!!

    c'que j'étais bien moi, pendant ma période suisse
    Héhé, oui, ici c'est la belle vie (on a nos problèmes aussi, mais globalement faut pas se plaindre)

    Si t'as besoin d'autres explications n'hésite pas.

    Ah dernière chose que je n'ai pas encore mentionné: essaie d'utiliser un outil de couverture de testing (dans intellij c'est intégré nativement -> Run all tests with coverage, sinon tu peux mettre en place un plugin maven (par exemple cobertura ou jacoco) qui produira de zolis rapports), ça te donnera rapidement une vision des morceaux de code qui manquent de test. Indicateur assez intéressant, même si c'est pas le Graal non plus...
    "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

  11. #51
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 523
    Points : 147
    Points
    147
    Par défaut
    Héhé, oui, ici c'est la belle vie (on a nos problèmes aussi, mais globalement faut pas se plaindre)
    oui je sais, 3 ans avec une Vaudoise au Jura, ça m'a fait bizarre le retour en France!
    mais bon c'était il y a +10 ans maintenant.


    Si t'as besoin d'autres explications n'hésite pas.
    disons que comme là on a fait une petite classe "service", oui, mais l'idée était d'essayer de poursuivre si possible avec:
    • un exemple de classe "controler"
    • une utilisant 1 webservice
    • une avec appel 1 API (sauf si principe identique à webservice?)
    • 1 classe data
    • 1 classe web, s'il y a un intérêt quelconque

    j'ai oublié quelque, chose en terme de panel des différents types de classes à tester?
    tu verrais encore autre chose?


    Ah dernière chose que je n'ai pas encore mentionné: essaie d'utiliser un outil de couverture de testing (dans intellij c'est intégré nativement -> Run all tests with coverage, sinon tu peux mettre en place un plugin maven (par exemple cobertura ou jacoco) qui produira de zolis rapports), ça te donnera rapidement une vision des morceaux de code qui manquent de test. Indicateur assez intéressant, même si c'est pas le Graal non plus...
    oui j'avais effectivement vu ce bouton, mais sans trop savoir à quoi ça correspondait, me suis donc contenté du run simple

  12. #52
    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 steph68b Voir le message
    oui je sais, 3 ans avec une Vaudoise au Jura
    Bin je suis jurassien mdr le plus beau canton de Suisse, que des bons vivants !

    Citation Envoyé par steph68b Voir le message
    disons que comme là on a fait une petite classe "service", oui, mais l'idée était d'essayer de poursuivre si possible avec:
    le reste c'est globalement pareil, sauf peut-être les controlleurs où l'on déclenche des requêtes http plutôt que d'invoquer des méthodes sur des objets. La config est un peu différentes, mais c'est la seule différence
    pour les value object (classe data), on peut utiliser ce genre d'outil: https://github.com/orien/bean-matchers, ça va tester tous les getters/setters/equals/hashcode/toString sans avoir à écrire les tests.

    Ce qu'il te manque maintenant, c'est les tests d'intégration, et ça, ça a aussi vraiment une grosse valeur ajoutée
    "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

  13. #53
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 523
    Points : 147
    Points
    147
    Par défaut
    Citation Envoyé par Pill_S Voir le message
    Bin je suis jurassien mdr le plus beau canton de Suisse, que des bons vivants !
    de quel coin? plateau? secteur Porren, Delé ou entre les deux?



    Citation Envoyé par Pill_S Voir le message
    le reste c'est globalement pareil, sauf peut-être les controlleurs où l'on déclenche des requêtes http plutôt que d'invoquer des méthodes sur des objets. La config est un peu différentes, mais c'est la seule différence
    pour les value object (classe data), on peut utiliser ce genre d'outil: https://github.com/orien/bean-matchers, ça va tester tous les getters/setters/equals/hashcode/toString sans avoir à écrire les tests.
    bon, vais déjà voir avec les dév, pour identifier une classe de chaque, je m'y colle et je verrai si je bloque ou pas
    beanmatcher c'est déjà du springboot (donc juste le pom à mettre à jour), ou produit tiers (install full à faire)?



    Citation Envoyé par Pill_S Voir le message
    Ce qu'il te manque maintenant, c'est les tests d'intégration, et ça, ça a aussi vraiment une grosse valeur ajoutée
    avant ça, GROS boulot de synthèse sur une doc à faire, j'ai lu tellement de trucs, appris d'autres ici avec toi.
    bref, j'ai des bouts de notes un peu partout, un beau merdier!

    après, la suite, on verra déjà selon les délais...

  14. #54
    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 steph68b Voir le message
    de quel coin? plateau? secteur Porren, Delé ou entre les deux?
    Porren (Courgenay en fait), mais j'ai bossé au Noirmont, ma copine vient de Dlem... disons qu'on fait vite le tour

    Citation Envoyé par steph68b Voir le message
    beanmatcher c'est déjà du springboot (donc juste le pom à mettre à jour), ou produit tiers (install full à faire)?
    Aucune idée mvn dependency:tree est ton ami. Disons que même si il faut l'installer, ça va surtout se limiter à ajouter ça dans le pom:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    <dependency>
        <groupId>com.google.code.bean-matchers</groupId>
        <artifactId>bean-matchers</artifactId>
        <version>0.11</version>
        <scope>test</scope>
    </dependency>
    (la magie de maven, ça n'a pas de prix)

    Citation Envoyé par steph68b Voir le message
    avant ça, GROS boulot de synthèse sur une doc à faire
    bon courage
    "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

  15. #55
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 523
    Points : 147
    Points
    147
    Par défaut
    Citation Envoyé par Pill_S Voir le message
    Porren (Courgenay en fait), mais j'ai bossé au Noirmont, ma copine vient de Dlem... disons qu'on fait vite le tour
    ah je vois très bien oui, j'allais chopper l'autoroute à courg', en venant de France, jusqu'à la sortie bassecourt
    le monde est petit!


    Citation Envoyé par Pill_S Voir le message
    Aucune idée mvn dependency:tree est ton ami.
    ok, en gros mvn dependency:tree | grep bean-master et voir si ça ramène qq chose ou pas


    Citation Envoyé par Pill_S Voir le message
    bon courage
    oui j'ai attaqué la 2ème méthode de la classe à tester (copyTemplate()) et je galère déjà MAIS je veux voir si j'y arrive solo!!


    bref, bon WE si jamais, et au secours lundi, si besoin!


    EDIT: comme dans setUp() on a
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    @Before
        public void setUp() throws Exception {
            mockCCBRepos = mock(CreationCampagneBlocRepository.class);
            instance = new CreationCampagneBlocService(mockCCBRepos);
        }
    comment se fait la désalloc' dans tearDown()?
    le GC n'étant pas sans faille, y a-t-il un truc à faire? juste passer mockCCBRepos + instance à null, par exemple? ou on laisse Java gérer?
    bref, quelle est la bonne pratique?

  16. #56
    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 steph68b Voir le message
    comment se fait la désalloc' dans tearDown()?
    le GC n'étant pas sans faille, y a-t-il un truc à faire? juste passer mockCCBRepos + instance à null, par exemple? ou on laisse Java gérer?
    bref, quelle est la bonne pratique?
    En général, il y a pas grand chose à faire. Tout dépend de comment sont initialisés les mocks, tu peux avoir besoin d'utiliser Mockito.reset(monmock) pour chacun des mocks dans le setUp, mais ça ne s'applique pas lorsqu'ils sont explicitement initialisés.

    Tout dépend de la config. On pourrait envisager que les mocks soient initialisés par Spring, puis injectés avec @Autowired dans les tests. Dans ce cas-là il faudrait les reseter.

    @After (tearDown), @BeforceClass et @AfterClass sont beaucoup moins utilisés. Très souvent, je n'ai aucune implém dans ces méthodes
    "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

  17. #57
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 523
    Points : 147
    Points
    147
    Par défaut
    Ok, c'est noté.

    Par contre, là, le timing s'accélère subitement et je dois produire qq chose!
    J'ai pris plein de notes partout, donc faut que je synthétise d'urgence, dans une belle doc!

    Donc pas possible de chercher pourquoi je bloque sur le test de la 2ème méthode!
    Tu pourrais voir, comme l'autre, stp?

    méthode base
    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
    public String copyTemplate(String idSource, String idTarget)
        {
            creationCampagneBlocRepository.requestLoging("https://xxxxxxxxxxxxxxx/qcbin/api/authentication/sign-in");
     
            String response = "";
     
            Copy entityTest = new Copy();
            entityTest.getID().add(idSource);
            entityTest.setTargetParentId(idTarget);
     
            ObjectRequest objectRequest = new ObjectRequest();
            objectRequest.setURLEntity("https://xxxxxxxxxxxxxxx/qcbin/rest/domains/DOM_G/projects/Greenwich_dev/test-set-folders/copy");
            objectRequest.setCopy(entityTest);
     
            try {
                response = creationCampagneBlocRepository.copyEntityWithURL(objectRequest).getBody().toString();
            } catch (Exception e) {
                e.printStackTrace();
            }
     
            creationCampagneBlocRepository.requestLoging("https://xxxxxxxxxxxxxxx/qcbin/api/authentication/sign-out");
     
            return response;
        }
    mon essai foireux (prblm de null pointer: ligne 35 getBody())
    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
    @Test
        public void copyTemplate() throws Exception {
            System.out.println("-> test unitaire de la méthode  <<< copyTemplate() >>>\n");
            //assertEquals(1,1);
     
            //*****************************************
            // GIVEN: quand la situation est comme ceci
            //*****************************************
                //paramètre en INPUT de la méthode
                String idSource="1", idTarget="2";
     
                Copy entityTest = new Copy();
                entityTest.getID().add(idSource);
                entityTest.setTargetParentId(idTarget);
     
                ObjectRequest objectRequest = new ObjectRequest();
                objectRequest.setURLEntity("https://xxxxxxxxxxxxxxx/qcbin/rest/domains/DOM_G/projects/Greenwich_dev/test-set-folders/copy");
                objectRequest.setCopy(entityTest);
     
     
            //********************************************************
            // WHEN: et que je fais cela (appeler la méthode à tester)
            //********************************************************
    //assertNull(mockCCBRepos.copyEntityWithURL(objectRequest).getBody());
    //assertNotNull(mockCCBRepos.copyEntityWithURL(objectRequest).getBody());
    // => !!! l'assert qui teste le statut 'null' plante car null pointer (????) !!!
     
                instance.copyTemplate(idSource, idTarget);
     
     
            //**************************************************************************
            // THEN: je m'attend à ce qu'il se passe ceci (tester le code de la méthode)
            //**************************************************************************
                verify(mockCCBRepos).requestLoging("https://xxxxxxxxxxxxxxx/qcbin/api/authentication/sign-in");
                verify(mockCCBRepos).copyEntityWithURL(objectRequest).getBody().toString();
                verify(mockCCBRepos).requestLoging("https://xxxxxxxxxxxxxxx/qcbin/api/authentication/sign-out");
        }
    Ensuite, je chercherai une méthode plus complexe, comme base de travail, parce que pas sûr du tout que je m'en sorte avec juste cette petite classe (peu remplie) quand je devrais répondre aux questions des dév'.....

    Merciiiiiiiiiiiiiiiiiiiii!

  18. #58
    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
    Il faudrait mocker le responseentity non?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    ResponseEntity mockEntity = Mockito.mock(ResponseEntity.class);
    Mockito.when(mockEntity.getBody()).thenReturn("un body");
    Mockito.when(creationCampagneBlocRepository.copyEntityWithURL(any())).thenReturn(mockEntity);
    Au niveau des verify, tu ne peux pas chainer les appels de la façon dont tu l'as fait. La syntaxe correcte pour vérifier que getBody a été invoqué, c'est de faire le verify sur mockEntity: Mockito.verify(mockEntity).getBody(); // puisque getBody retourne une string, verify s'arrête là, il ne peut pas aller vérifier plus loin - la classe String ne dispose pas des comportement permettant d'enregistrer ce qui a été exécuté.
    "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

  19. #59
    Membre habitué
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 523
    Points : 147
    Points
    147
    Par défaut
    Je ne testais peut être pas de la bonne manière, mais le problème est en amont.

    Je suis vite sorti de ma doc de synthèse pour reprendre le code et ce qui déclenche le null pointer c'est dans la classe de test, l'appel à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    String idSource="1", idTarget="2";
    instance.copyTemplate(idSource, idTarget);
    qui va lancer dans la classe de base
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Copy entityTest = new Copy();
    entityTest.getID().add(idSource);
    entityTest.setTargetParentId(idTarget);
    
    ObjectRequest objectRequest = new ObjectRequest();
    objectRequest.setCopy(entityTest);
    
    response = creationCampagneBlocRepository.copyEntityWithURL(objectRequest).getBody().toString();
    qui à priori fonctionne bien de cette manière.

    Mon idée:
    - à priori, idSource & idTarget initialisent mal le entityTest qui sera lui même utilisé pour pour le objectRequest utilisé par copyEntityWithURL()
    - le getBody() renvoie null car il ne doit pas trouver de body pour idSource="1" & idTarget="2"
    - je dois donc voir avec le dév' de la classe pour qu'il me donne des IDs cohérents

    Ça tient la route comme analyse?

  20. #60
    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
    Nop, désolé mais je ne pense pas.

    Je te rappelle que repository est un mock. Il retourne null par défaut pour toutes les méthodes dont tu ne précises pas le comportement. Il ne retourne que ce que tu lui a initialisé. Il ne contient pratiquement aucune logique, et encore moins la logique de la classe originale.

    creationCampagneBlocRepository.copyEntityWithURL(objectRequest) retourne donc null par défaut si tu n'as rien spécifié de plus. Je pense que le problème est là.

    Avec ton débuggeur, en mode pas à pas, vérifie le type des objets qui sont manipulés. Tout ce que tu verras du type XXX$EnhancedByMockito, c'est des mocks et c'est inerte.
    "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

Discussions similaires

  1. [Toutes versions] test Front End/Back End
    Par Mr.Mof dans le forum Modélisation
    Réponses: 2
    Dernier message: 22/05/2012, 11h29
  2. Tests unitaires en Java
    Par identifiant_bidon dans le forum Général Java
    Réponses: 4
    Dernier message: 23/08/2011, 14h50
  3. Réponses: 0
    Dernier message: 22/03/2010, 09h41
  4. [JUnit] test unitaire et java
    Par fk04 dans le forum Tests et Performance
    Réponses: 4
    Dernier message: 10/09/2007, 23h02

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