Différences
Ci-dessous, les différences entre deux révisions de la page.
Prochaine révision | Révision précédente | ||
eadl:bloc3:dev_av:td2-b [2025/10/08 00:30] – créée jcheron | eadl:bloc3:dev_av:td2-b [2025/10/08 01:32] (Version actuelle) – [10. Exercice pratique] jcheron | ||
---|---|---|---|
Ligne 18: | Ligne 18: | ||
=== 2.1 Dépendances Maven === | === 2.1 Dépendances Maven === | ||
- | <code xml> | + | <sxh xml> |
< | < | ||
<!-- Spring Boot Test (inclut JUnit 5, Mockito, AssertJ) --> | <!-- Spring Boot Test (inclut JUnit 5, Mockito, AssertJ) --> | ||
Ligne 42: | Ligne 42: | ||
</ | </ | ||
</ | </ | ||
- | </code> | + | </sxh> |
=== 2.2 Configuration de test (application-test.properties) === | === 2.2 Configuration de test (application-test.properties) === | ||
- | <code properties> | + | <sxh bash> |
# src/ | # src/ | ||
Ligne 68: | Ligne 68: | ||
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE | logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE | ||
logging.level.org.hibernate.orm.jdbc.bind=TRACE | logging.level.org.hibernate.orm.jdbc.bind=TRACE | ||
- | </code> | + | </sxh> |
==== 3. Anatomie d'un test JPA ==== | ==== 3. Anatomie d'un test JPA ==== | ||
Ligne 74: | Ligne 74: | ||
=== 3.1 Test Repository basique === | === 3.1 Test Repository basique === | ||
- | <code java> | + | <sxh java> |
@DataJpaTest | @DataJpaTest | ||
@ActiveProfiles(" | @ActiveProfiles(" | ||
Ligne 103: | Ligne 103: | ||
} | } | ||
} | } | ||
- | </code> | + | </sxh> |
<WRAP round tip> | <WRAP round tip> | ||
Ligne 114: | Ligne 114: | ||
=== 3.2 TestEntityManager - Les commandes clés === | === 3.2 TestEntityManager - Les commandes clés === | ||
- | <code java> | + | <sxh java> |
@Test | @Test | ||
void demonstrateTestEntityManager() { | void demonstrateTestEntityManager() { | ||
Ligne 134: | Ligne 134: | ||
entityManager.detach(fromDb); | entityManager.detach(fromDb); | ||
} | } | ||
- | </code> | + | </sxh> |
==== 4. Tests des associations ==== | ==== 4. Tests des associations ==== | ||
Ligne 140: | Ligne 140: | ||
=== 4.1 OneToMany bidirectionnel === | === 4.1 OneToMany bidirectionnel === | ||
- | <code java> | + | <sxh java> |
@Test | @Test | ||
void shouldCascadeOrderToOrderItems() { | void shouldCascadeOrderToOrderItems() { | ||
Ligne 166: | Ligne 166: | ||
.containsExactlyInAnyOrder(" | .containsExactlyInAnyOrder(" | ||
} | } | ||
- | </code> | + | </sxh> |
=== 4.2 Problème N+1 - Détection === | === 4.2 Problème N+1 - Détection === | ||
- | <code java> | + | <sxh java> |
@Test | @Test | ||
void shouldDetectNPlusOneProblem() { | void shouldDetectNPlusOneProblem() { | ||
Ligne 210: | Ligne 210: | ||
// assertSelectCount(1); | // assertSelectCount(1); | ||
} | } | ||
- | </code> | + | </sxh> |
==== 5. Tests des requêtes JPQL ==== | ==== 5. Tests des requêtes JPQL ==== | ||
Ligne 216: | Ligne 216: | ||
=== 5.1 Query basique === | === 5.1 Query basique === | ||
- | <code java> | + | <sxh java> |
@Test | @Test | ||
void shouldFindProductsByPriceRange() { | void shouldFindProductsByPriceRange() { | ||
Ligne 237: | Ligne 237: | ||
.containsExactly(" | .containsExactly(" | ||
} | } | ||
- | </code> | + | </sxh> |
=== 5.2 Projection DTO === | === 5.2 Projection DTO === | ||
- | <code java> | + | <sxh java> |
public record ProductSummary(UUID id, String name, BigDecimal price) {} | public record ProductSummary(UUID id, String name, BigDecimal price) {} | ||
Ligne 263: | Ligne 263: | ||
assertThat(summaries.get(0).name()).isEqualTo(" | assertThat(summaries.get(0).name()).isEqualTo(" | ||
} | } | ||
- | </code> | + | </sxh> |
==== 6. Tests avec données initiales ==== | ==== 6. Tests avec données initiales ==== | ||
Ligne 269: | Ligne 269: | ||
=== 6.1 Via fichier SQL === | === 6.1 Via fichier SQL === | ||
- | <code java> | + | <sxh java> |
@Test | @Test | ||
@Sql("/ | @Sql("/ | ||
Ligne 276: | Ligne 276: | ||
assertThat(products).hasSizeGreaterThan(0); | assertThat(products).hasSizeGreaterThan(0); | ||
} | } | ||
- | </code> | + | </sxh> |
Fichier '' | Fichier '' | ||
- | <code sql> | + | <sxh sql> |
INSERT INTO product (id, name, price, stock) VALUES | INSERT INTO product (id, name, price, stock) VALUES | ||
(' | (' | ||
(' | (' | ||
- | </code> | + | </sxh> |
=== 6.2 Via méthode @BeforeEach === | === 6.2 Via méthode @BeforeEach === | ||
- | <code java> | + | <sxh java> |
@DataJpaTest | @DataJpaTest | ||
class OrderRepositoryTest { | class OrderRepositoryTest { | ||
Ligne 315: | Ligne 315: | ||
} | } | ||
} | } | ||
- | </code> | + | </sxh> |
==== 7. Tests des contraintes ==== | ==== 7. Tests des contraintes ==== | ||
Ligne 321: | Ligne 321: | ||
=== 7.1 Validation Bean Validation === | === 7.1 Validation Bean Validation === | ||
- | <code java> | + | <sxh java> |
@Test | @Test | ||
void shouldFailWhenEmailInvalid() { | void shouldFailWhenEmailInvalid() { | ||
Ligne 337: | Ligne 337: | ||
.hasMessageContaining(" | .hasMessageContaining(" | ||
} | } | ||
- | </code> | + | </sxh> |
=== 7.2 Contrainte unique === | === 7.2 Contrainte unique === | ||
- | <code java> | + | <sxh java> |
@Test | @Test | ||
void shouldFailOnDuplicateEmail() { | void shouldFailOnDuplicateEmail() { | ||
Ligne 357: | Ligne 357: | ||
.isInstanceOf(DataIntegrityViolationException.class); | .isInstanceOf(DataIntegrityViolationException.class); | ||
} | } | ||
- | </code> | + | </sxh> |
==== 8. Testcontainers (DB réelle) ==== | ==== 8. Testcontainers (DB réelle) ==== | ||
- | <code java> | + | <sxh java> |
@DataJpaTest | @DataJpaTest | ||
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) | @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) | ||
Ligne 391: | Ligne 391: | ||
} | } | ||
} | } | ||
- | </code> | + | </sxh> |
==== 9. Bonnes pratiques ==== | ==== 9. Bonnes pratiques ==== | ||
Ligne 412: | Ligne 412: | ||
==== 10. Exercice pratique ==== | ==== 10. Exercice pratique ==== | ||
- | <WRAP round box> | + | <WRAP round todo> |
**À implémenter :** | **À implémenter :** | ||
Créer les tests d' | Créer les tests d' | ||
- | - [ ] Test de création d'une review avec associations | + | - Test de création d'une review avec associations |
- | - [ ] Test de la contrainte '' | + | - Test de la contrainte '' |
- | - [ ] Test unicité (user, product) | + | - Test unicité (user, product) |
- | - [ ] Test du chargement avec '' | + | - Test du chargement avec '' |
- | - [ ] Test de calcul de moyenne des ratings par produit | + | - Test de calcul de moyenne des ratings par produit |
- | - [ ] Test de la projection '' | + | - Test de la projection '' |
</ | </ | ||