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

Spring Boot Java Discussion :

Test Unitaires, mon Exception est bien levée mais ne renvoie le message attendu


Sujet :

Spring Boot Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2023
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2023
    Messages : 3
    Par défaut Test Unitaires, mon Exception est bien levée mais ne renvoie le message attendu
    Bonjour à tous,

    Je suis nouveau sur le forum, je débute en Java

    J'utilise Java 20 avec Maven depuis Eclipse IDE 2023-06
    J'utilise Spring 6.0.11

    Vous trouverez mon fichier pom.xml ainsi que mes différentes classes en PJ

    Au départ, j'avais plusieurs classes d'Exceptions et dans mon Service, j'avais mis en place le code nécessaire pour lancer chaque exception selon les différents cas
    Ca fonctionnait bien

    Mon souhait désormais serait de me passer de ces classes d'Exception et d'utiliser les annotations à la place
    J'ai donc supprimé mes Exception et enlever le code spécifique de mon service
    J'ai ensuite ajouté les annotation nécessaires sur mon modèle Utilisateur :

    @NotBlank(message = "Le nom d'utilisateur doit-être renseigné")
    @Size(min = 3, max = 50, message = "Le nom d'utilisateur doit contenir entre {min} et {max} caractères")

    Et j'ai modifié mon Test unitaire
    Seulement maintenant, pour mes "test de failure", par exemple testCreerUtilisateurLimiteTailleNomUtilisateur :
    L'Exception ConstraintViolationException est bien levée mais un getMessage() dessus me renvoie null au lieu de "Le nom d'utilisateur doit contenir entre {min} et {max} caractères"

    J'ai essayé de rechercher sur le net et aussi avec ChatGPT, mais je n'arrive as à trouver l'origine du problème
    Si c'est nécessaire, je pourrait toutefois retourner à mon ancienne méthode avec des exception levée "manuellement" dans mon service mais je trouverais ça dommage de ne pas utiliser les fonctions d'annotations existantes

    En vous remerciant par avance

    Un jeune débutant en Java
    Fichiers attachés Fichiers attachés

  2. #2
    Membre très actif

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    486
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 486
    Billets dans le blog
    5
    Par défaut
    Ca me fatigue de chercher un programme pour ouvrir les .java.
    De plus, sur notre forum, la balise code existe.

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    public MaClasseJava{
      //ect
    }

  3. #3
    Candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2023
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2023
    Messages : 3
    Par défaut
    Bonjour,

    Désolé de vous avoir froissé
    Comme dit je suis nouveau sur le forum et je pensais que pour que vous puissiez répondre au mieux à une question, il était de bon usage de fournir le code utilisé
    Surtout que pour ouvrir un .java, un simple bloc note peut suffire...
    Toutefois j'en prends note pour mes futurs posts

    Si vous le souhaitez, voilà une partie de mon code :
    Utilisateur.java :
    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
    @Entity
    @Table(name = "utilisateurs")
    public class Utilisateur {
    	@Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
     
    	@Column(name = "nom_utilisateur", length = 50)
    	@NotBlank(message = "Le nom d'utilisateur doit-être renseigné")
    	@Size(min = 3, max = 50, message = "Le nom d'utilisateur doit contenir entre {min} et {max} caractères")
        private String nomUtilisateur;
     
        @Column(name = "mot_de_passe", length = 100)
        @NotBlank(message = "Le mot de passe doit-être renseigné")
    	@Size(min = 10, max = 50, message = "Le mot de passe doit contenir entre {min} et {max} caractères")
        @Pattern(regexp = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[@#$%^&+=]).{10,}$",
        		message = "Le mot de passe doit contenir au moins 10 caractères, une majuscule, un chiffre et un caractère spécial")
        private String motDePasse;
    ...
    et UtilisateurService.java
    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
    @Service
    public class UtilisateurService {
     
        @Autowired
        private UtilisateurRepository utilisateurRepository;
     
        @Autowired
        private BCryptPasswordEncoder passwordEncoder;
     
        public Utilisateur creerUtilisateur(Utilisateur utilisateur) {
     
        	String motDePasseCrypte = passwordEncoder.encode(utilisateur.getMotDePasse());
            utilisateur.setMotDePasse(motDePasseCrypte);
     
            return utilisateurRepository.save(utilisateur);
        }
    ...
    Et enfin mon TestUtilisateurService.java
    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
    class UtilisateurServiceTest {
     
    	@Mock
        private UtilisateurRepository utilisateurRepository;
     
        @InjectMocks
        private UtilisateurService utilisateurService;
     
        @Spy
        private UtilisateurService utilisateurServiceSpy;
     
        @Autowired
        private BCryptPasswordEncoder passwordEncoder;
     
        @BeforeEach
        void setUp() {
        	MockitoAnnotations.openMocks(this);
        	passwordEncoder = mock(BCryptPasswordEncoder.class);
            utilisateurService = new UtilisateurService(); // Réinitialisez l'objet utilisateurService avec le passwordEncoder simulé.
            utilisateurService.setUtilisateurRepository(utilisateurRepository);
            utilisateurService.setPasswordEncoder(passwordEncoder);
        }
     
        @Test
        void testCreerUtilisateurLimiteTailleNomUtilisateur() {
            Utilisateur utilisateur = new Utilisateur();
            utilisateur.setNomUtilisateur("123456789012345678901234567890123456789012345678901"); // 51 caractères
            utilisateur.setMotDePasse("12345678901234567890");
     
            // Simuler l'échec de l'enregistrement avec la taille du nom utilisateur trop grande
            doThrow(ConstraintViolationException.class)
                    .when(utilisateurRepository).save(utilisateur);
     
            ConstraintViolationException exception = assertThrows(ConstraintViolationException.class, () -> {
                utilisateurService.creerUtilisateur(utilisateur);
            });
     
            assertEquals("Le nom d'utilisateur doit contenir entre 3 et 50 caractères", exception.getMessage());
     
            // Vérifier que la méthode save a été appelée
            verify(utilisateurRepository, times(1)).save(utilisateur);
        }
    ...
    Merci d'avance

    Cordialement,

  4. #4
    Membre très actif

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    486
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 486
    Billets dans le blog
    5
    Par défaut
    Je pense que il y a des notions manquantes sur ce qu'est un test.

    Je vais donc essayer de les combler en me basant sur mon projet ( https://bitbucket.org/philippegibaul...r40k/src/main/ ).

    Le premier test: le TU:

    C'est le test de base. Il est là pour tester une fonctionnalité. On l'écrit en général avant le code, pour plein de raison, notamment car on définit le pourquoi, le contrat, avant le comment.

    Exemple: Soit les Space Marine, qui utilisent la règles Serment de l'instant. Quand la cible est la cible choisie, on relance les touches et les blesses.
    Soit le TU pour les données d'entrées:
    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
     
    package com.calculateur.warhammer.data.regles.factory.regle.detachement.space.marine;
     
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Set;
     
    import org.assertj.core.api.Assertions;
    import org.junit.jupiter.api.Test;
    import org.mockito.Mockito;
     
    import com.calculateur.warhammer.base.exception.FunctionnalExeption;
    import com.calculateur.warhammer.data.regles.IRegleAttaque;
    import com.calculateur.warhammer.data.regles.detachement.space.marine.ESermentInstantChoix;
    import com.calculateur.warhammer.data.regles.factory.regle.AbstractFactoryRegleTest;
     
    public class RegleDetachementSermentInstantFactoryTest extends AbstractFactoryRegleTest{
     
    	public RegleDetachementSermentInstantFactoryTest() {
    		super(new RegleDetachementSermentInstantFactory());
    	}
     
    	@Override
    	protected boolean isRegleAttaqueAttendu() {
    		return true;
    	}
     
    	@Override
    	protected boolean isRegleDefenseAttendu() {
    		return false;
    	}
     
    	@Test
    	public void validePresenceChoixSermentInstant() throws Exception{
    		validateExceptionsDonneesObligatoire(ESermentInstantChoix.ID_CHOIX_SERMENT_INSTANT, true);
    	}
     
    	@Test
    	public void testSermentInstant() throws FunctionnalExeption{
    		IRegleAttaque regle;
    		for(ESermentInstantChoix choix:ESermentInstantChoix.values()) {
    			initMock(choix);
    			regle = factoryRegle.getRegleAttaque(donnees,getDefaultParameterAttaque());
    			valideSermentInstant(regle, choix);
    		}
    	}
     
    	private void initMock(ESermentInstantChoix choix) {
    		parameters.clear();
    		parameters.put(ESermentInstantChoix.ID_CHOIX_SERMENT_INSTANT, choix.getIdSermentInstant());
    		Mockito.when(donnees.getDonneesAttaquant()).thenReturn(parameters);
    	}
     
    	private void valideSermentInstant(IRegleAttaque regle,ESermentInstantChoix choix) {
    		Set<Integer> attendu = (choix == ESermentInstantChoix.OUI)?(new HashSet<>(Arrays.asList(1,2,3,4,5,6))):Collections.emptySet();
    		Assertions.assertThat(regle.getScoreJetToucheRelancable()).isEqualTo(attendu);
    		Assertions.assertThat(regle.getScoreJetBlessureRelancable()).isEqualTo(attendu);
    	}
     
    	@Override
    	protected Integer getDefaultParameterAttaque() {
    		return null;
    	}
    }
    Notez que les données d'entrées sont mocké avec Mockito.
    Notez que je ne teste pas une classe dans un TU, mais ici un ensemble de classe (la Factory + la règle).

    Ce qui donne pour la règle:
    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
     
    package com.calculateur.warhammer.data.regles.detachement.space.marine;
     
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Set;
     
    import com.calculateur.warhammer.data.regles.IRegleAttaque;
     
    /**
     * Règle serment de l'instant. Si les spaces marines utilisent cette règle, alors ils reances les jets de touches et de blessures.
     * @author phili
     *
     */
    public class RegleDetachementSermentInstant implements IRegleAttaque{
     
    	private final Set<Integer> relances;
     
    	public RegleDetachementSermentInstant(ESermentInstantChoix choix) {
    		relances = (choix == ESermentInstantChoix.OUI)?(new HashSet<>(Arrays.asList(1,2,3,4,5,6))):Collections.emptySet();
    	}
     
    	@Override
    	public Set<Integer> getScoreJetToucheRelancable() {
    		return getRelances();
    	}
     
    	@Override
    	public Set<Integer> getScoreJetBlessureRelancable() {
    		return getRelances();
    	}
     
    	private Set<Integer> getRelances() {
    		return relances;
    	}
    }
    Et la Factory:
    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
     
    package com.calculateur.warhammer.data.regles.factory.regle.detachement.space.marine;
     
    import com.calculateur.warhammer.base.exception.FunctionnalExeption;
    import com.calculateur.warhammer.data.regles.IRegleAttaque;
    import com.calculateur.warhammer.data.regles.IRegleDefense;
    import com.calculateur.warhammer.data.regles.detachement.space.marine.RegleDetachementSermentInstant;
    import com.calculateur.warhammer.data.regles.factory.donnees.IDonneeFactory;
    import com.calculateur.warhammer.data.regles.factory.regle.IFactoryRegle;
     
    public class RegleDetachementSermentInstantFactory implements IFactoryRegle{
     
    	@Override
    	public IRegleAttaque getRegleAttaque(IDonneeFactory donnees,Integer parameter) throws FunctionnalExeption {
    		return new RegleDetachementSermentInstant(SpaceMarineDetachamentUtils.getSermetInstant(donnees.getDonneesAttaquant()));
    	}
     
    	@Override
    	public IRegleDefense getRegleDefense(IDonneeFactory donnees) throws FunctionnalExeption {
    		return null;
    	}
     
    	@Override
    	public boolean isRegleApplicableAttaque() {
    		return true;
    	}
     
    	@Override
    	public boolean isRegleApplicableDefense() {
    		return false;
    	}
     
    }
    Deuxième type de test: le test d'intégration:
    Là, on fait un test pour savoir si on s'intègre bien à une BDD. On test en gros ... Les DAO. Comme toi, j'utilise Hibernate Validator pour tester si l'utilisateur entre les bonnes données.
    A notez que là, je ne mock rien. Je construis une configuration avec Spring. En ce qui me concerne, comme les tests sont plus ou moins toujours identiques, et que je n'aime pas me répéter, j'utilise le Design Pattern Template Method ( https://fr.wikipedia.org/wiki/Patron_de_m%C3%A9thode ). Je l'utilise aussi pour mes DAO.

    A noter que la BDD de prod est Postgres là où celle de test est H2. C'est du au fait que grâce à JPA, je peux changer de BDD cible.
    Donc pour l'entité:
    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
     
    package com.calculateur.warhammer.entity.entity;
     
    import java.util.Set;
     
    import jakarta.persistence.Column;
    import jakarta.persistence.Entity;
    import jakarta.persistence.FetchType;
    import jakarta.persistence.Id;
    import jakarta.persistence.OneToMany;
    import jakarta.persistence.Table;
    import jakarta.validation.constraints.NotNull;
     
     
    @Entity
    @Table(name = "CAMP")
    public class CampEntity extends AbstractEntityAvecLibelle<Integer>{
     
    	@Id
    	@Column(name = "ID_CAMP",nullable = false)
    	@NotNull(message = "id.null")
    	private Integer id;
     
    	@OneToMany(mappedBy = "camp",fetch = FetchType.LAZY)
    	private Set<FactionEntity> factions;
     
    	@Override
    	public Integer getId() {
    		return id;
    	}
     
    	@Override
    	public void setId(Integer id) {
    		this.id = id;
    	}
     
    	public Set<FactionEntity> getFactions() {
    		return factions;
    	}
     
    	public void setFactions(Set<FactionEntity> factions) {
    		this.factions = factions;
    	}
    }
    J'ai le test suivant (avec Template Method):
    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
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
     
    package com.calculateur.warhammer.base.dao;
     
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
     
    import org.assertj.core.api.Assertions;
     
    import com.calculateur.warhammer.base.builder.AbstractEntityAvecLibelleBuilder;
    import com.calculateur.warhammer.base.entity.IEntityAvecLibelle;
     
    /**
     * TU pour DAO de IEntityAvecLibelle
     * @author phili
     *
     * @param <I> Type id
     * @param <E> Entité
     */
    public abstract class AbstractEntityAvecLibelleDAOTest<I extends Serializable,E extends IEntityAvecLibelle<I>,B extends AbstractEntityAvecLibelleBuilder<I, E>> extends AbstractDAOTest<I, E, IDAO<I,E>>{
     
    	protected static final Integer ID_TEST = Integer.MAX_VALUE -1;
    	protected static final Integer ID_RIEN = Integer.MAX_VALUE;
     
    	/**
             * 
             * @return Un identifiant valide pour les tests
             */
    	protected abstract I getValidId();
     
    	/**
             * 
             * @return Un builder préparé avec les bonnes données de test
             */
    	protected B getBuilderPrepare() {
    		B builder = getBuilder();
    		builder.addId(getValidId()).addNom(STRING_TEST).addCleTraduction(STRING_TEST);
    		addAutreAttributsAuBuilder(builder);
    		return builder;
    	}
     
    	/**
             * 
             * @return Une nouvelle instance du Builder
             */
    	protected abstract B getBuilder();
     
    	/**
             * Pour configurer le builder, on ajoute ici les autres attributs (autre que le nom ety la clé de traduction)
             * @param builder Un builder
             */
    	protected abstract void addAutreAttributsAuBuilder(B builder);
     
    	@Override
    	protected List<E> getErrorsEntities() {
    		List<E> list = new ArrayList<>();
    		//Id null
    		list.add(getBuilderPrepare().addId(null).build());
    		//Erreurs sur les identifiants
    		list.addAll(getErreursSurId());
    		//Nom
    		list.add(getBuilderPrepare().addNom(null).build());
    		list.add(getBuilderPrepare().addNom(EMPTY_STRING).build());
    		list.add(getBuilderPrepare().addNom(getToLongString(50)).build());
    		//Clé de traduction
    		list.add(getBuilderPrepare().addCleTraduction(null).build());
    		list.add(getBuilderPrepare().addCleTraduction(EMPTY_STRING).build());
    		list.add(getBuilderPrepare().addCleTraduction(getToLongString(50)).build());
    		//Autres erreurs
    		list.addAll(getAutresErreurs());
    		return list;
    	}
     
    	/**
             * 
             * @return Une liste d'entité ayant une erreur sur les identifiants (hors id null)
             */
    	protected abstract List<E> getErreursSurId();
     
    	/**
             * 
             * @return Les autres erreurs
             */
    	protected abstract List<E> getAutresErreurs();
     
    	@Override
    	protected E getEntityForInsertion() {
    		return getBuilderPrepare().build();
    	}
     
    	@Override
    	protected void updateEntity(E toUpdate) {
    		toUpdate.setNom(STRING_TEST2);
    		toUpdate.setCleTraduction(STRING_TEST2);
    		updateAutresAttributs(toUpdate);
    	}
     
    	/**
             * Mise � jour des attributs autres que le nom et la clé de traduction
             * @param toUpdate Entitée mettre à jour
             */
    	protected abstract void updateAutresAttributs(E toUpdate);
     
    	@Override
    	protected void assertUpdate(E anEntity) {
    		Assertions.assertThat(anEntity.getNom()).isEqualTo(STRING_TEST2);
    		Assertions.assertThat(anEntity.getCleTraduction()).isEqualTo(STRING_TEST2);
    		assertUpdateAutreAttribut(anEntity);
    	}
     
    	/**
             * Vérifie la mise à jour des attributs autres que le nom et le libellé
             * @param anEntity Entité tester
             */
    	protected abstract void assertUpdateAutreAttribut(E anEntity);
    }
    Le 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
    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
    69
    70
    71
    72
    73
    74
    75
     
    package com.calculateur.warhammer.dao.dao;
     
    import java.util.Collections;
    import java.util.List;
     
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit.jupiter.SpringExtension;
     
    import com.calculateur.warhammer.base.dao.AbstractEntityAvecLibelleDAOTest;
    import com.calculateur.warhammer.base.dao.IDAO;
    import com.calculateur.warhammer.dao.configuration.ConfigurationTestBDDH2;
    import com.calculateur.warhammer.entity.builder.CampEntityBuilder;
    import com.calculateur.warhammer.entity.entity.CampEntity;
     
    @ExtendWith(SpringExtension.class)
    @SpringBootTest(classes = {ConfigurationTestBDDH2.class})
    public class CampDAOTest extends AbstractEntityAvecLibelleDAOTest<Integer, CampEntity,CampEntityBuilder>{
     
    	@Autowired
    	private IDAO<Integer, CampEntity> campDAO;
     
    	@Override
    	protected Integer getValidId() {
    		return ID_TEST;
    	}
     
    	@Override
    	protected CampEntityBuilder getBuilder() {
    		return CampEntityBuilder.getInstance();
    	}
     
    	@Override
    	protected void addAutreAttributsAuBuilder(CampEntityBuilder builder) {
    		//Rien
    	}
     
    	@Override
    	protected List<CampEntity> getErreursSurId() {
    		return Collections.emptyList();
    	}
     
    	@Override
    	protected List<CampEntity> getAutresErreurs() {
    		return Collections.emptyList();
    	}
     
    	@Override
    	protected void updateAutresAttributs(CampEntity toUpdate) {
    		//Rien
    	}
     
    	@Override
    	protected void assertUpdateAutreAttribut(CampEntity anEntity) {
    		//rien
    	}
     
    	@Override
    	protected IDAO<Integer, CampEntity> getDAO() {
    		return campDAO;
    	}
     
    	@Override
    	protected Integer getIdWithNothingInDatabase() {
    		return ID_RIEN;
    	}
     
    	@Override
    	protected void testSupplementaires(CampEntity entityTest) {
    		//Rien
    	}
     
    }
    Je me base sur la configuration:
    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
     
    package com.calculateur.warhammer.dao.configuration;
     
    import java.io.File;
    import org.springframework.context.annotation.Configuration;
     
    import com.calculateur.warhammer.dao.configuration.general.AbstractConfigurationH2;
    import com.calculateur.warhammer.dao.h2.ConfigurationH2;
     
    @Configuration
    public class ConfigurationTestBDDH2 extends AbstractConfigurationH2{
     
    	@Override
    	protected ConfigurationH2 getConfigurationH2() {
    		return new ConfigurationH2(getFolderDatabase(), getFolderCopy(), ConfigurationH2Test.PORT, ConfigurationH2Test.DATABASE_PATH,
    				ConfigurationH2Test.DATABASE_SCHEMA);
    	}
     
    	@Override
    	protected boolean isShowSQL() {
    		return false;
    	}
     
    	@Override
    	protected boolean isCreateSchema() {
    		return false;
    	}
     
    	private File getFolderDatabase() {
    		return new File(ConfigurationH2Test.PATH_FOLDER_BASE_DB);
    	}
     
    	private File getFolderCopy() {
    		return new File(ConfigurationH2Test.PATH_FOLDER_COPY_DB);
    	}
     
    }
    Et pour l'implémentation (on peut faire autrement):
    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
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
     
    package com.calculateur.warhammer.dao.dao;
     
    import java.util.List;
    import java.util.Optional;
     
    import jakarta.persistence.EntityManager;
    import jakarta.persistence.PersistenceContext;
    import jakarta.persistence.Query;
     
     
    import org.springframework.transaction.PlatformTransactionManager;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.support.DefaultTransactionDefinition;
     
    import com.calculateur.warhammer.base.dao.IDAO;
    import com.calculateur.warhammer.base.entity.IEntity;
    import com.calculateur.warhammer.base.exception.DAOException;
    import com.calculateur.warhammer.base.exception.FunctionnalExeption;
    import com.calculateur.warhammer.dao.verification.VerificationUtils;
     
     
    /**
     * Template Method pour les DAO avec JPA
     * @author phili
     *
     * @param <I> Type de l'id
     * @param <E> Type de l'entité
     */
    public abstract class AbstractDAO<I,E extends IEntity<I>> implements IDAO<I, E>{
     
    	@PersistenceContext
    	protected final EntityManager em;
     
    	protected final PlatformTransactionManager transactionManager;
     
    	protected AbstractDAO(EntityManager em, PlatformTransactionManager transactionManager) {
    		this.em = em;
    		this.transactionManager = transactionManager;
    	}
     
    	/**
             * 
             * @return La classe sous forme de String pour les Query JPQL
             */
    	protected abstract String getEntityClass();
     
    	/**
             * 
             * @return Le libellé de l'entité pour les query JPQL
             */
    	protected abstract String getEntityLibelle();
     
    	/**
             * 
             * @return Le resource Bundle d'erreur pour les erreurs fonctionnelles
             */
    	protected abstract String getErrorBundle();
     
    	/**
             * 
             * @return L'entit� sous forme de classe
             */
    	protected abstract Class<E> getClassEntity();
     
    	@Override
    	public E save(E entity) throws DAOException, FunctionnalExeption {
    		verifieEntity(entity);
    		TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
    		try {
    			em.persist(entity);
    			transactionManager.commit(status);
    			return entity;
    		}catch (Exception e) {
    			transactionManager.rollback(status);
    			throw new DAOException(e);
    		}
    	}
     
    	@Override
    	public E update(E entity) throws DAOException, FunctionnalExeption {
    		verifieEntity(entity);
    		TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
    		try {
    			E rEntity = em.merge(entity);
    			transactionManager.commit(status);
    			return rEntity;
    		}catch (Exception e) {
    			transactionManager.rollback(status);
    			throw new DAOException(e);
    		}
    	}
     
    	@Override
    	public Optional<E> getById(I id) throws DAOException {
    		try {
    			return Optional.ofNullable(em.find(getClassEntity(), id));
    		}catch(Exception e) {
    			throw new DAOException(e);
    		}
    	}
     
    	@SuppressWarnings("unchecked")
    	@Override
    	public List<E> getAll() throws DAOException {
    		try {
    			Query query = em.createQuery(getJpqlAll());
    			return query.getResultList();
    		}catch(Exception e) {
    			throw new DAOException(e);
    		}
    	}
     
    	/**
             * 
             * @return Le JPQL pour avoir toutes les entités
             */
    	private String getJpqlAll() {
    		StringBuilder sb = new StringBuilder("SELECT ");
    		sb.append(getEntityLibelle());
    		sb.append(" FROM ");
    		sb.append(getEntityClass());
    		sb.append(" ");
    		sb.append(getEntityLibelle());
    		return sb.toString();
    	}
     
    	@Override
    	public void delete(I id) throws DAOException {
    		TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
    		try {
    			Query queryDelete = getDeleteQuery(id);
    			queryDelete.executeUpdate();
    			transactionManager.commit(status);
    		}catch(Exception e) {
    			transactionManager.rollback(status);
    			throw new DAOException(e);
    		}
     
    	}
     
    	/**
             * On laisse la possibilité de surcharger cette méthode au cas où l'id soit complexe (clé sur 2 colonnes par exemple).
             * @param id L'id de l'entité à supprimer en BDD.
             * @return La query pour effacer l'entit� (le paramétrage est fait.
             */
    	protected Query getDeleteQuery(I id) {
    		Query query = em.createQuery(getDeleteJpql());
    		query.setParameter("id", id);
    		return query;
    	}
     
    	/**
             * On laisse la possibilité de surcharger cette méthode au cas où l'id soit complexe (clé sur 2 colonnes par exemple).
             * @return JPQL pour suprimer une entité
             */
    	protected String getDeleteJpql() {
    		StringBuilder sb = new StringBuilder("DELETE ");
    		sb.append(" FROM ");
    		sb.append(getEntityClass());
    		sb.append(" ");
    		sb.append(getEntityLibelle());
    		sb.append(" WHERE ");
    		sb.append(getEntityLibelle());
    		sb.append(".id = : id");
    		return sb.toString();
    	}
     
    	@Override
    	public Long count() throws DAOException {
    		try {
    			Query query = em.createQuery(getJpqlCount());
    			return (Long) query.getSingleResult();
    		}catch (Exception e) {
    			throw new DAOException(e);
    		}
    	}
     
    	/**
             * 
             * @return Le JPQL pour compter ce qui est en BDD.
             */
    	private String getJpqlCount() {
    		StringBuilder sb = new StringBuilder("SELECT DISTINCT(COUNT(");
    		sb.append(getEntityLibelle());
    		sb.append(")) FROM ");
    		sb.append(getEntityClass());
    		sb.append(" ");
    		sb.append(getEntityLibelle());
    		return sb.toString();
    	}
     
    	@Override
    	public void verifieEntity(E entity) throws DAOException, FunctionnalExeption {
    		VerificationUtils.verifie(entity, getErrorBundle());
    	}
    }
    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
     
    package com.calculateur.warhammer.dao.dao;
     
    import jakarta.persistence.EntityManager;
     
    import org.springframework.stereotype.Repository;
    import org.springframework.transaction.PlatformTransactionManager;
     
    import com.calculateur.warhammer.entity.entity.CampEntity;
     
    /**
     * DAO de CampEntity
     * @author phili
     *
     */
    @Repository
    public class CampDAO extends AbstractDAO<Integer, CampEntity>{
     
    	private static final String ENTITY_CLASS = "CampEntity";
     
    	private static final String ENTITY_LIBELLE = "campEntity";
     
    	private static final String RES = "com.calculateur.warhammer.entity.camp.camp";
     
    	public CampDAO(EntityManager em, PlatformTransactionManager transactionManager) {
    		super(em, transactionManager);
    	}
     
    	@Override
    	protected String getEntityClass() {
    		return ENTITY_CLASS;
    	}
     
    	@Override
    	protected String getEntityLibelle() {
    		return ENTITY_LIBELLE;
    	}
     
    	@Override
    	protected String getErrorBundle() {
    		return RES;
    	}
     
    	@Override
    	protected Class<CampEntity> getClassEntity() {
    		return CampEntity.class;
    	}
     
    }
    Notez que pour ce que tu veux faire, le code utile est celui-ci:
    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
     
    package com.calculateur.warhammer.dao.verification;
     
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
     
    import jakarta.validation.ConstraintViolation;
    import jakarta.validation.Validation;
    import jakarta.validation.Validator;
    import jakarta.validation.ValidatorFactory;
     
    import com.calculateur.warhammer.base.exception.FunctionnalExeption;
     
    /**
     * Classe de vérification utile
     * @author phili
     *
     */
    public class VerificationUtils {
     
    	private VerificationUtils() {
     
    	}
     
    	/**
             * Vérifie la cohérence des données selon Hibernate Validation
             * @param aVerifier Objet à vérifier
             * @param resource Resource Bundle d'erreur sous forme de String
             * @throws FunctionnalExeption Si erreur de validation
             */
    	public static void verifie(Object aVerifier, String resource) throws FunctionnalExeption {
    		ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    	    Validator validator = factory.getValidator();
    	    Set<ConstraintViolation<Object>> constraintViolations = validator.validate(aVerifier);
    	    List<String> errors = new ArrayList<>();
    	    for(ConstraintViolation<Object> contraint:constraintViolations) {
    	    	errors.add(contraint.getMessage());
    	    }
    	    if(!errors.isEmpty()) {
    	    	throw new FunctionnalExeption(errors, resource);
    	    }
    	}
    }
    Le Test Back-end:
    Il n'est pas dans la problématique que tu soulèves, mais il peut aussi avoir son intérêt. Tu as un test où tu envois un JSON et tu vérifie qu'un service REST envoit le bon JSON de retour. Tu testes un service REST.

    Dans mon projet, j'ai fait par configuration Spring, testant une intégration de la BDD jusqu'au controller en passant par les services. Mais au travail, j'utilise un système de Mock.
    Exemple:
    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
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
     
    package com.calculateur.warhammer.rest.controller;
     
    import static org.junit.jupiter.api.Assertions.fail;
     
    import java.util.Arrays;
    import java.util.List;
     
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.MediaType;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.ResultActions;
    import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
    import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
     
    import com.calculateur.warhammer.base.dto.ILibelleDTO;
    import com.calculateur.warhammer.base.dto.ILibelleEtDescriptionDTO;
    import com.calculateur.warhammer.base.service.IServiceRechercheExistant;
    import com.calculateur.warhammer.dto.contrat.IDTOparEnumeration;
     
     
    public abstract class AbstractListRestControllerTest<DTO extends ILibelleDTO,S extends IServiceRechercheExistant<DTO>> {
     
    	protected static final String[] LOCALES = {"fr","en"};
     
    	protected static final String LOCALE_NON_IMPLEMENTEE = "zz";
     
    	protected static final int PRECONDITION_FAILED = 412;
     
    	private static final String URL_ALL = "/all/";
     
    	@Autowired
    	protected MockMvc mvc;
    	/**
             * 
             * @return L'url du contrôleur
             */
    	protected abstract String getUrlController();
     
    	/**
             * 
             * @return Le service de test
             */
    	protected abstract S getService();
     
    	@Test
    	public void doTestGetAllOK() {
    		Arrays.asList(LOCALES).stream().forEach(l -> doTestGetAllOK(l));
    	}
     
    	private void doTestGetAllOK(String langue) {
    		try {
    			List<DTO> list = getService().liste(langue);
    			ResultActions action = mvc.perform(MockMvcRequestBuilders
    					.get(getUrlAll(langue))
    					.accept(MediaType.APPLICATION_JSON_VALUE))
    					.andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(list.size()))
    					.andExpect(MockMvcResultMatchers.status().isOk());
    			for(int i = 0; i < list.size();i++) {
    				valideDTO(action, i, list.get(i));
    			}
    			action.andReturn();
    		} catch (Exception e) {
    			fail(e);
    		}
    	}
     
    	@Test
    	public void testAllLangueNonImplementee(){
    		try {
    			mvc.perform(MockMvcRequestBuilders
    					.get(getUrlAll(LOCALE_NON_IMPLEMENTEE))
    					.accept(MediaType.APPLICATION_JSON_VALUE))
    					.andExpect(MockMvcResultMatchers.status().is(PRECONDITION_FAILED)).andReturn();
    		} catch (Exception e) {
    			fail(e);
    		}
    	}
     
    	/**
             * 
             * @param position Position
             * @param champ Champ testé
             * @return Le JSON pour test à la position i
             */
    	protected String getTestJsonForPosition(int position,String champ) {
    		StringBuilder sb = new StringBuilder();
    		sb.append("$.[");
    		sb.append(position);
    		sb.append("].");
    		sb.append(champ);
    		return sb.toString();
    	}
     
    	private String getUrlAll(String locale) {
    		StringBuilder url = new StringBuilder();
    		url.append(getUrlController());
    		url.append(URL_ALL);
    		url.append(locale);
    		return url.toString();
    	}
     
    	protected void valideDTO(ResultActions action, int i, DTO dto) throws Exception {
    		action.andExpect(MockMvcResultMatchers.jsonPath(getTestJsonForPosition(i, "id")).value(dto.getId()));
    		action.andExpect(MockMvcResultMatchers.jsonPath(getTestJsonForPosition(i, "libelle")).value(dto.getLibelle()));
    		action.andExpect(MockMvcResultMatchers.jsonPath(getTestJsonForPosition(i, "cleTraduction")).value(dto.getCleTraduction()));
    		if(dto instanceof ILibelleEtDescriptionDTO des) {
    			action.andExpect(MockMvcResultMatchers.jsonPath(getTestJsonForPosition(i, "description")).value(des.getDescription()));	
    		}
    		if(dto instanceof IDTOparEnumeration<?> en) {
    			action.andExpect(MockMvcResultMatchers.jsonPath(getTestJsonForPosition(i, "enumeration")).value(en.getEnumeration().toString()));
    		}
    	}
    }
    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
     
    package com.calculateur.warhammer.rest.controller;
     
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.web.servlet.ResultActions;
    import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
     
    import com.calculateur.warhammer.base.service.IServiceRechercheExistant;
    import com.calculateur.warhammer.dto.CampDTO;
    import com.calculateur.warhammer.rest.configuration.ConfigurationRestTest;
     
    @ContextConfiguration(classes = {ConfigurationRestTest.class})
    @WebMvcTest
    public class CampControllerTest extends AbstractListRestControllerTest<CampDTO,IServiceRechercheExistant<CampDTO>>{
     
    	private static final String URL_CAMP_CONTROLLER = "/camp";
     
    	@Autowired
    	private IServiceRechercheExistant<CampDTO> campService;
     
    	@Override
    	protected String getUrlController() {
    		return URL_CAMP_CONTROLLER;
    	}
     
    	@Override
    	protected IServiceRechercheExistant<CampDTO> getService() {
    		return campService;
    	}
     
    	@Override
    	protected void valideDTO(ResultActions action, int i, CampDTO dto) throws Exception {
    		super.valideDTO(action, i, dto);
    		action.andExpect(MockMvcResultMatchers.jsonPath(getTestJsonForPosition(i, "nom")).value(dto.getNom()));
    	}
    }
    Et comme implémentation:
    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
     
    package com.calculateur.warhammer.rest.controller;
     
    import java.util.List;
     
    import org.springframework.http.MediaType;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.ResponseBody;
     
    import com.calculateur.warhammer.base.dto.ILibelleDTO;
    import com.calculateur.warhammer.base.exception.FunctionnalExeption;
    import com.calculateur.warhammer.base.exception.ServiceException;
    import com.calculateur.warhammer.base.service.IServiceRechercheExistant;
     
    /**
     * Template Methode pour les service qui récère un ensemble de DTO
     * @author phili
     *
     * @param <D> DTO
     * @param <S> Le type de service utilisé
     */
    public abstract class AbstractListRestController<D extends ILibelleDTO,S extends IServiceRechercheExistant<D>> extends AbstractRestController{
     
    	/**
             * 
             * @return Le service utilisé par le controlleur
             */
    	protected abstract S getService();
     
    	@GetMapping(value = "/all/{langue}",produces = {MediaType.APPLICATION_JSON_VALUE})
    	@ResponseBody
    	public ResponseEntity<List<D>> getAll(@PathVariable("langue")String langue)throws ServiceException,FunctionnalExeption{
    		return ResponseEntity.ok(getService().liste(langue));
    	}
    }
    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
     
    package com.calculateur.warhammer.rest.controller;
     
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
     
    import com.calculateur.warhammer.base.service.IServiceRechercheExistant;
    import com.calculateur.warhammer.dto.CampDTO;
     
    @RestController
    @RequestMapping("/camp")
    public class CampController extends AbstractListRestController<CampDTO,IServiceRechercheExistant<CampDTO>>{
     
    	private IServiceRechercheExistant<CampDTO> campService;
     
    	public CampController(IServiceRechercheExistant<CampDTO> campService) {
    		this.campService = campService;
    	}
     
    	@Override
    	protected IServiceRechercheExistant<CampDTO> getService() {
    		return campService;
    	}
    }
    Conclusion:
    Le test est une problématique complexe. Il faut toujours faire du test et être dans une logique de TDD.

    En ce qui me concerne, je pense que tu cherche à tester le fait que quand l'utilisateur a un login trop long, tu renvoies une erreur.
    Avec la logique Spring, tu as un controlleur dans lequel tu injecte le service dans lequel tu as injecter la DAO.

    C'est la DAO qui va envoyer l'exception. Ce que tu fais a un sens dans un test sur la DAO.

  5. #5
    Membre éclairé Avatar de Chou-ette
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2018
    Messages
    57
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 27
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2018
    Messages : 57
    Par défaut
    Citation Envoyé par Arkaroi Voir le message
    Comme dit je suis nouveau sur le forum et je pensais que pour que vous puissiez répondre au mieux à une question, il était de bon usage de fournir le code utilisé
    Surtout que pour ouvrir un .java, un simple bloc note peut suffire...
    Toutefois j'en prends note pour mes futurs posts
    Vous avez eu un bon réflexe en voulant fournir le code qui vous pose problème, il est cependant d'usage d'isoler les quelques blocs de code les plus intéressants avec la balise code, et de ne fournir le projet entier que sur demande si des échanges par petits morceaux ne suffisent pas

  6. #6
    Candidat au Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2023
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2023
    Messages : 3
    Par défaut
    Bonjour,

    Merci pour votre réponse très détaillée
    Comme je débute, je ne suis pas sur de tout comprendre, je vais donc me permettre de poser plusieurs questions ?
    Merci également d'avoir partagé votre projet, je vais m'en inspirer pour progresser même si dans un premier temps, étant débutant je vais essayer de faire les choses par moi-même quitte à défaire pour refaire etc.. pour vraiment bien comprendre et apprendre

    Il est vrai que ma vision était d'avoir une classe de test pour chaque modèle
    Par exemple, ici, j'ais une classe Utilisateur. Je suis parti dans l'idée de créer une classe de Test pour tester le select, l'insert, l'update et le delete dans des cas qui se passent bien
    Et d'autres tests dans des cas qui génèreraient des erreurs (insert avec champ nom d'utilisateur trop long par exemple), pour vérifier que l'erreur est levée (c'est le cas) ET que le message d'erreur obtenu soit celui auquel je m'attends (ce qui me pose problème car dans mon Test, la ligne "exception.getMessage()" renvoie null au lieu de "Le nom d'utilisateur doit contenir entre 3 et 50 caractères")
    Le tout en partant de ma classe de service

    Si j'ai bien compris, ces tests devraient être faits depuis la DAO plutot que depuis le service ?

    Pour ma dao, j'étais parti sur le fait d'utiliser tout simplement une JPARepository
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    package repository;
     
    import model.Utilisateur;
    import org.springframework.data.jpa.repository.JpaRepository;
     
    public interface UtilisateurRepository extends JpaRepository<Utilisateur, Long> {
     
    }
    Est-ce une mauvaise idée?
    Mieux vaut-il créer soi-même sa propre DAO comme vous l'avez fait ?

    Me conseilleriez-vous plutôt d'écrire moi même le code de vérification ainsi que les exceptions particulières pour ce type d'erreur
    Plutot que de me baser uniquement sur les annotations pour les controles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    @Size(min = 3, max = 50, message = "Le nom d'utilisateur doit contenir entre {min} et {max} caractères")
    ?

    C'est ce que j'avais fait auparavant en ajoutant les contrôles dans mon service :

    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
    public Utilisateur creerUtilisateur(Utilisateur utilisateur) {
        	if (utilisateur.getNomUtilisateur() == null || utilisateur.getNomUtilisateur().isEmpty()) {
                throw new ChampNonRenseigneException("Nom d'utilisateur");
            }
     
        	if (utilisateur.getNomUtilisateur().length() > 50) {
                throw new ChampTropGrandException("Nom d'utilisateur", 50, utilisateur.getNomUtilisateur().length());
            }
     
            if (utilisateur.getMotDePasse() == null || utilisateur.getMotDePasse().isEmpty()) {
                throw new ChampNonRenseigneException("Mot de passe");
            }
     
        	if (utilisateur.getMotDePasse().length() > 100) {
                throw new ChampTropGrandException("Mot de passe", 100, utilisateur.getMotDePasse().length());
            }
     
        	String motDePasseCrypte = passwordEncoder.encode(utilisateur.getMotDePasse());
            utilisateur.setMotDePasse(motDePasseCrypte);
     
            return utilisateurRepository.save(utilisateur);
        }
    Mon Exception :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package exception;
     
    public class ChampTropGrandException extends RuntimeException {
    	private String champ;
     
        public ChampTropGrandException(String champ, int tailleMax, int tailleVal) {
            super("Le champ " + champ + " (" + tailleVal +") dépasse la taille limite (" + tailleMax +").");
            this.champ = champ;
        }
     
        public String getChamp() {
            return champ;
        }
    }
    Mon 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
    @Test
        void testCreerUtilisateurLimiteTailleNomUtilisateur() {
            Utilisateur utilisateur = new Utilisateur();
            utilisateur.setNomUtilisateur("123456789012345678901234567890123456789012345678901"); // 51 caractères
     
            doThrow(ChampTropGrandException.class)
                .when(utilisateurRepository).save(utilisateur);
     
            ChampTropGrandException exception = assertThrows(ChampTropGrandException.class, () -> {
                utilisateurService.creerUtilisateur(utilisateur);
            });
     
            assertEquals("Nom d'utilisateur", exception.getChamp());
        }
    Mais j'avais pensé que ce serait une bonne idée de me baser uniquement sur les annotations pour simplifier mon Service et ne pas avoir à créer une multitude d'exceptions différentes pour chacuns des d'erreur possible
    Mais peut-etre est-ce une mauvaise idée ?

    Je vous remercie encore de l'aide que vous m'apportez en tout cas !

  7. #7
    Membre très actif

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    486
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 486
    Billets dans le blog
    5
    Par défaut
    Pour commencer, il faut différentier les couches.

    La couche qui tape la BDD est la couche Entité.

    La couche service manipule des DTO. Des DTO pour transférer vers l'extérieur.



    Je te recommande de différentier la DTO (UtilisateurDTO) de l'entité (UtilisateurEntity). Ce dernier mappe la BDD avec JPA.

    De fait, c'est un test d'intégration que tu fais, test qui effectivement le test de la classe UtilisateurRepository.
    BDD H2 étant la plus pertinente pour les tests, et qui n'est pas la même que celle de prod (possible grâce à l'utilisation de Hibernate).

    Néanmoins, dans ton cas, afin entre autre d'avoir la logique de vérification dans le repository (car c'est là qu'on le fait effectivement), et si tu ne veux pas coder à la dure une classe avec un EntityManager (ce que je peux comprendre), tu peux utiliser le Design Pattern Adaptateur:
    https://fr.wikipedia.org/wiki/Adapta...de_conception)

    Le mieux est de définir toi-même ta repository, indépendamment de Spring. Dans l'implémentation réelle, tu va injecter une DAO Spring, et c'est dans l’implémentation réelle que tu vas vérifier ta règle métier avec Hibernate Validation.

    De plus, adaptateur Pattern va avec l'idée que c'est Spring qui s'adapte à tes besoins, et non l'inverse.
    Et ça va, à plus long terme, avec l'architecture Hexagonale:

Discussions similaires

  1. [Python 3.X] RESOLU : Tester qu'une exception est bien levée
    Par Arioch dans le forum Général Python
    Réponses: 7
    Dernier message: 20/05/2022, 09h56
  2. Réponses: 0
    Dernier message: 16/10/2012, 13h39
  3. Comment m'assurer que mon fichier est bien un exec unix
    Par Khaled.Noordin dans le forum Apple
    Réponses: 5
    Dernier message: 05/07/2007, 18h37
  4. [CF][C#]Comment déterminer si mon PPC est bien connecté?
    Par royrremi dans le forum Windows Mobile
    Réponses: 2
    Dernier message: 07/03/2006, 15h35

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