Alignement design systeme OK
This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
package dev.lions.unionflow.server.resource;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.membre.MembreSearchCriteria;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import io.quarkus.test.security.TestSecurity;
|
||||
import io.restassured.http.ContentType;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
/**
|
||||
* Tests d'intégration pour l'endpoint de recherche avancée des membres
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-19
|
||||
*/
|
||||
@QuarkusTest
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
class MembreResourceAdvancedSearchTest {
|
||||
|
||||
private static final String ADVANCED_SEARCH_ENDPOINT = "/api/membres/search/advanced";
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
@TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit fonctionner avec critères valides")
|
||||
void testAdvancedSearchWithValidCriteria() {
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.query("marie")
|
||||
.statut("ACTIF")
|
||||
.ageMin(20)
|
||||
.ageMax(50)
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(criteria)
|
||||
.queryParam("page", 0)
|
||||
.queryParam("size", 20)
|
||||
.queryParam("sort", "nom")
|
||||
.queryParam("direction", "asc")
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("membres", notNullValue())
|
||||
.body("totalElements", greaterThanOrEqualTo(0))
|
||||
.body("totalPages", greaterThanOrEqualTo(0))
|
||||
.body("currentPage", equalTo(0))
|
||||
.body("pageSize", equalTo(20))
|
||||
.body("hasNext", notNullValue())
|
||||
.body("hasPrevious", equalTo(false))
|
||||
.body("isFirst", equalTo(true))
|
||||
.body("executionTimeMs", greaterThan(0))
|
||||
.body("statistics", notNullValue())
|
||||
.body("statistics.membresActifs", greaterThanOrEqualTo(0))
|
||||
.body("statistics.membresInactifs", greaterThanOrEqualTo(0))
|
||||
.body("criteria.query", equalTo("marie"))
|
||||
.body("criteria.statut", equalTo("ACTIF"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
@TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit fonctionner avec critères multiples")
|
||||
void testAdvancedSearchWithMultipleCriteria() {
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.email("@unionflow.com")
|
||||
.dateAdhesionMin(LocalDate.of(2020, 1, 1))
|
||||
.dateAdhesionMax(LocalDate.of(2025, 12, 31))
|
||||
.roles(List.of("ADMIN", "SUPER_ADMIN"))
|
||||
.includeInactifs(false)
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(criteria)
|
||||
.queryParam("page", 0)
|
||||
.queryParam("size", 10)
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("membres", notNullValue())
|
||||
.body("totalElements", greaterThanOrEqualTo(0))
|
||||
.body("criteria.email", equalTo("@unionflow.com"))
|
||||
.body("criteria.roles", hasItems("ADMIN", "SUPER_ADMIN"))
|
||||
.body("criteria.includeInactifs", equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
@TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit gérer la pagination")
|
||||
void testAdvancedSearchPagination() {
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.includeInactifs(true) // Inclure tous les membres
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(criteria)
|
||||
.queryParam("page", 0)
|
||||
.queryParam("size", 2) // Petite taille pour tester la pagination
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("currentPage", equalTo(0))
|
||||
.body("pageSize", equalTo(2))
|
||||
.body("isFirst", equalTo(true))
|
||||
.body("hasPrevious", equalTo(false));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
@TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit gérer le tri")
|
||||
void testAdvancedSearchSorting() {
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.statut("ACTIF")
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(criteria)
|
||||
.queryParam("sort", "nom")
|
||||
.queryParam("direction", "desc")
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("membres", notNullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
@TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit retourner 400 pour critères vides")
|
||||
void testAdvancedSearchWithEmptyCriteria() {
|
||||
MembreSearchCriteria emptyCriteria = MembreSearchCriteria.builder().build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(emptyCriteria)
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(400)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("message", containsString("Au moins un critère de recherche doit être spécifié"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
@TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit retourner 400 pour critères invalides")
|
||||
void testAdvancedSearchWithInvalidCriteria() {
|
||||
MembreSearchCriteria invalidCriteria = MembreSearchCriteria.builder()
|
||||
.ageMin(50)
|
||||
.ageMax(30) // Âge max < âge min
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(invalidCriteria)
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(400)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("message", containsString("Critères de recherche invalides"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(7)
|
||||
@TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit retourner 400 pour body null")
|
||||
void testAdvancedSearchWithNullBody() {
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(400);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(8)
|
||||
@TestSecurity(user = "marie.active@unionflow.com", roles = {"MEMBRE_ACTIF"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit retourner 403 pour utilisateur non autorisé")
|
||||
void testAdvancedSearchUnauthorized() {
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.query("test")
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(criteria)
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(403);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(9)
|
||||
@DisplayName("POST /api/membres/search/advanced doit retourner 401 pour utilisateur non authentifié")
|
||||
void testAdvancedSearchUnauthenticated() {
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.query("test")
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(criteria)
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(401);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(10)
|
||||
@TestSecurity(user = "admin@unionflow.com", roles = {"ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit fonctionner pour ADMIN")
|
||||
void testAdvancedSearchForAdmin() {
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.statut("ACTIF")
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(criteria)
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("membres", notNullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(11)
|
||||
@TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit inclure le temps d'exécution")
|
||||
void testAdvancedSearchExecutionTime() {
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.query("test")
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(criteria)
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("executionTimeMs", greaterThan(0))
|
||||
.body("executionTimeMs", lessThan(5000)); // Moins de 5 secondes
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(12)
|
||||
@TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit retourner des statistiques complètes")
|
||||
void testAdvancedSearchStatistics() {
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.includeInactifs(true)
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(criteria)
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("statistics", notNullValue())
|
||||
.body("statistics.membresActifs", greaterThanOrEqualTo(0))
|
||||
.body("statistics.membresInactifs", greaterThanOrEqualTo(0))
|
||||
.body("statistics.ageMoyen", greaterThanOrEqualTo(0.0))
|
||||
.body("statistics.ageMin", greaterThanOrEqualTo(0))
|
||||
.body("statistics.ageMax", greaterThanOrEqualTo(0))
|
||||
.body("statistics.nombreOrganisations", greaterThanOrEqualTo(0))
|
||||
.body("statistics.ancienneteMoyenne", greaterThanOrEqualTo(0.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(13)
|
||||
@TestSecurity(user = "superadmin@unionflow.com", roles = {"SUPER_ADMIN"})
|
||||
@DisplayName("POST /api/membres/search/advanced doit gérer les caractères spéciaux")
|
||||
void testAdvancedSearchWithSpecialCharacters() {
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.query("marie-josé")
|
||||
.nom("o'connor")
|
||||
.build();
|
||||
|
||||
given()
|
||||
.contentType(ContentType.JSON)
|
||||
.body(criteria)
|
||||
.when()
|
||||
.post(ADVANCED_SEARCH_ENDPOINT)
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("membres", notNullValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,409 @@
|
||||
package dev.lions.unionflow.server.service;
|
||||
|
||||
import dev.lions.unionflow.server.api.dto.membre.MembreSearchCriteria;
|
||||
import dev.lions.unionflow.server.api.dto.membre.MembreSearchResultDTO;
|
||||
import dev.lions.unionflow.server.entity.Membre;
|
||||
import dev.lions.unionflow.server.entity.Organisation;
|
||||
import io.quarkus.panache.common.Page;
|
||||
import io.quarkus.panache.common.Sort;
|
||||
import io.quarkus.test.junit.QuarkusTest;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.transaction.Transactional;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Tests pour la recherche avancée de membres
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-19
|
||||
*/
|
||||
@QuarkusTest
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
class MembreServiceAdvancedSearchTest {
|
||||
|
||||
@Inject
|
||||
MembreService membreService;
|
||||
|
||||
private static Organisation testOrganisation;
|
||||
private static List<Membre> testMembres;
|
||||
|
||||
@BeforeAll
|
||||
@Transactional
|
||||
static void setupTestData() {
|
||||
// Créer une organisation de test
|
||||
testOrganisation = Organisation.builder()
|
||||
.nom("Organisation Test")
|
||||
.typeOrganisation("ASSOCIATION")
|
||||
.statut("ACTIF")
|
||||
.actif(true)
|
||||
.dateCreation(LocalDateTime.now())
|
||||
.build();
|
||||
testOrganisation.persist();
|
||||
|
||||
// Créer des membres de test avec différents profils
|
||||
testMembres = List.of(
|
||||
// Membre actif jeune
|
||||
Membre.builder()
|
||||
.numeroMembre("UF-2025-TEST001")
|
||||
.nom("Dupont")
|
||||
.prenom("Marie")
|
||||
.email("marie.dupont@test.com")
|
||||
.telephone("+221701234567")
|
||||
.dateNaissance(LocalDate.of(1995, 5, 15))
|
||||
.dateAdhesion(LocalDate.of(2023, 1, 15))
|
||||
.roles("MEMBRE,SECRETAIRE")
|
||||
.actif(true)
|
||||
.organisation(testOrganisation)
|
||||
.dateCreation(LocalDateTime.now())
|
||||
.build(),
|
||||
|
||||
// Membre actif âgé
|
||||
Membre.builder()
|
||||
.numeroMembre("UF-2025-TEST002")
|
||||
.nom("Martin")
|
||||
.prenom("Jean")
|
||||
.email("jean.martin@test.com")
|
||||
.telephone("+221701234568")
|
||||
.dateNaissance(LocalDate.of(1970, 8, 20))
|
||||
.dateAdhesion(LocalDate.of(2020, 3, 10))
|
||||
.roles("MEMBRE,PRESIDENT")
|
||||
.actif(true)
|
||||
.organisation(testOrganisation)
|
||||
.dateCreation(LocalDateTime.now())
|
||||
.build(),
|
||||
|
||||
// Membre inactif
|
||||
Membre.builder()
|
||||
.numeroMembre("UF-2025-TEST003")
|
||||
.nom("Diallo")
|
||||
.prenom("Fatou")
|
||||
.email("fatou.diallo@test.com")
|
||||
.telephone("+221701234569")
|
||||
.dateNaissance(LocalDate.of(1985, 12, 3))
|
||||
.dateAdhesion(LocalDate.of(2021, 6, 5))
|
||||
.roles("MEMBRE")
|
||||
.actif(false)
|
||||
.organisation(testOrganisation)
|
||||
.dateCreation(LocalDateTime.now())
|
||||
.build(),
|
||||
|
||||
// Membre avec email spécifique
|
||||
Membre.builder()
|
||||
.numeroMembre("UF-2025-TEST004")
|
||||
.nom("Sow")
|
||||
.prenom("Amadou")
|
||||
.email("amadou.sow@unionflow.com")
|
||||
.telephone("+221701234570")
|
||||
.dateNaissance(LocalDate.of(1988, 3, 12))
|
||||
.dateAdhesion(LocalDate.of(2022, 9, 20))
|
||||
.roles("MEMBRE,TRESORIER")
|
||||
.actif(true)
|
||||
.organisation(testOrganisation)
|
||||
.dateCreation(LocalDateTime.now())
|
||||
.build()
|
||||
);
|
||||
|
||||
// Persister tous les membres
|
||||
testMembres.forEach(membre -> membre.persist());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
@Transactional
|
||||
static void cleanupTestData() {
|
||||
// Nettoyer les données de test
|
||||
if (testMembres != null) {
|
||||
testMembres.forEach(membre -> {
|
||||
if (membre.isPersistent()) {
|
||||
membre.delete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (testOrganisation != null && testOrganisation.isPersistent()) {
|
||||
testOrganisation.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(1)
|
||||
@DisplayName("Doit effectuer une recherche par terme général")
|
||||
void testSearchByGeneralQuery() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.query("marie")
|
||||
.build();
|
||||
|
||||
// When
|
||||
MembreSearchResultDTO result = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 10), Sort.by("nom"));
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getTotalElements()).isEqualTo(1);
|
||||
assertThat(result.getMembres()).hasSize(1);
|
||||
assertThat(result.getMembres().get(0).getPrenom()).isEqualToIgnoringCase("Marie");
|
||||
assertThat(result.isFirst()).isTrue();
|
||||
assertThat(result.isLast()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
@DisplayName("Doit filtrer par statut actif")
|
||||
void testSearchByActiveStatus() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.statut("ACTIF")
|
||||
.build();
|
||||
|
||||
// When
|
||||
MembreSearchResultDTO result = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 10), Sort.by("nom"));
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getTotalElements()).isEqualTo(3); // 3 membres actifs
|
||||
assertThat(result.getMembres()).hasSize(3);
|
||||
assertThat(result.getMembres()).allMatch(membre -> "ACTIF".equals(membre.getStatut()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
@DisplayName("Doit filtrer par tranche d'âge")
|
||||
void testSearchByAgeRange() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.ageMin(25)
|
||||
.ageMax(35)
|
||||
.build();
|
||||
|
||||
// When
|
||||
MembreSearchResultDTO result = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 10), Sort.by("nom"));
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getTotalElements()).isGreaterThan(0);
|
||||
|
||||
// Vérifier que tous les membres sont dans la tranche d'âge
|
||||
result.getMembres().forEach(membre -> {
|
||||
if (membre.getDateNaissance() != null) {
|
||||
int age = LocalDate.now().getYear() - membre.getDateNaissance().getYear();
|
||||
assertThat(age).isBetween(25, 35);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(4)
|
||||
@DisplayName("Doit filtrer par période d'adhésion")
|
||||
void testSearchByAdhesionPeriod() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.dateAdhesionMin(LocalDate.of(2022, 1, 1))
|
||||
.dateAdhesionMax(LocalDate.of(2023, 12, 31))
|
||||
.build();
|
||||
|
||||
// When
|
||||
MembreSearchResultDTO result = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 10), Sort.by("dateAdhesion"));
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getTotalElements()).isGreaterThan(0);
|
||||
|
||||
// Vérifier que toutes les dates d'adhésion sont dans la période
|
||||
result.getMembres().forEach(membre -> {
|
||||
if (membre.getDateAdhesion() != null) {
|
||||
assertThat(membre.getDateAdhesion())
|
||||
.isAfterOrEqualTo(LocalDate.of(2022, 1, 1))
|
||||
.isBeforeOrEqualTo(LocalDate.of(2023, 12, 31));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(5)
|
||||
@DisplayName("Doit rechercher par email avec domaine spécifique")
|
||||
void testSearchByEmailDomain() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.email("@unionflow.com")
|
||||
.build();
|
||||
|
||||
// When
|
||||
MembreSearchResultDTO result = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 10), Sort.by("nom"));
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getTotalElements()).isEqualTo(1);
|
||||
assertThat(result.getMembres()).hasSize(1);
|
||||
assertThat(result.getMembres().get(0).getEmail()).contains("@unionflow.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(6)
|
||||
@DisplayName("Doit filtrer par rôles")
|
||||
void testSearchByRoles() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.roles(List.of("PRESIDENT", "SECRETAIRE"))
|
||||
.build();
|
||||
|
||||
// When
|
||||
MembreSearchResultDTO result = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 10), Sort.by("nom"));
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getTotalElements()).isGreaterThan(0);
|
||||
|
||||
// Vérifier que tous les membres ont au moins un des rôles recherchés
|
||||
result.getMembres().forEach(membre -> {
|
||||
assertThat(membre.getRole()).satisfiesAnyOf(
|
||||
role -> assertThat(role).contains("PRESIDENT"),
|
||||
role -> assertThat(role).contains("SECRETAIRE")
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(7)
|
||||
@DisplayName("Doit gérer la pagination correctement")
|
||||
void testPagination() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.includeInactifs(true) // Inclure tous les membres
|
||||
.build();
|
||||
|
||||
// When - Première page
|
||||
MembreSearchResultDTO firstPage = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 2), Sort.by("nom"));
|
||||
|
||||
// Then
|
||||
assertThat(firstPage).isNotNull();
|
||||
assertThat(firstPage.getCurrentPage()).isEqualTo(0);
|
||||
assertThat(firstPage.getPageSize()).isEqualTo(2);
|
||||
assertThat(firstPage.getMembres()).hasSizeLessThanOrEqualTo(2);
|
||||
assertThat(firstPage.isFirst()).isTrue();
|
||||
|
||||
if (firstPage.getTotalElements() > 2) {
|
||||
assertThat(firstPage.isLast()).isFalse();
|
||||
assertThat(firstPage.isHasNext()).isTrue();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(8)
|
||||
@DisplayName("Doit calculer les statistiques correctement")
|
||||
void testStatisticsCalculation() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.includeInactifs(true) // Inclure tous les membres
|
||||
.build();
|
||||
|
||||
// When
|
||||
MembreSearchResultDTO result = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 10), Sort.by("nom"));
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getStatistics()).isNotNull();
|
||||
|
||||
MembreSearchResultDTO.SearchStatistics stats = result.getStatistics();
|
||||
assertThat(stats.getMembresActifs()).isEqualTo(3);
|
||||
assertThat(stats.getMembresInactifs()).isEqualTo(1);
|
||||
assertThat(stats.getAgeMoyen()).isGreaterThan(0);
|
||||
assertThat(stats.getAgeMin()).isGreaterThan(0);
|
||||
assertThat(stats.getAgeMax()).isGreaterThan(stats.getAgeMin());
|
||||
assertThat(stats.getAncienneteMoyenne()).isGreaterThanOrEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(9)
|
||||
@DisplayName("Doit retourner un résultat vide pour critères impossibles")
|
||||
void testEmptyResultForImpossibleCriteria() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.query("membre_inexistant_xyz")
|
||||
.build();
|
||||
|
||||
// When
|
||||
MembreSearchResultDTO result = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 10), Sort.by("nom"));
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getTotalElements()).isEqualTo(0);
|
||||
assertThat(result.getMembres()).isEmpty();
|
||||
assertThat(result.isEmpty()).isTrue();
|
||||
assertThat(result.getTotalPages()).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(10)
|
||||
@DisplayName("Doit valider la cohérence des critères")
|
||||
void testCriteriaValidation() {
|
||||
// Given - Critères incohérents
|
||||
MembreSearchCriteria invalidCriteria = MembreSearchCriteria.builder()
|
||||
.ageMin(50)
|
||||
.ageMax(30) // Âge max < âge min
|
||||
.build();
|
||||
|
||||
// When & Then
|
||||
assertThat(invalidCriteria.isValid()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(11)
|
||||
@DisplayName("Doit avoir des performances acceptables (< 500ms)")
|
||||
void testSearchPerformance() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.includeInactifs(true)
|
||||
.build();
|
||||
|
||||
// When & Then - Mesurer le temps d'exécution
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
MembreSearchResultDTO result = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 20), Sort.by("nom"));
|
||||
|
||||
long executionTime = System.currentTimeMillis() - startTime;
|
||||
|
||||
// Vérifications
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(executionTime).isLessThan(500L); // Moins de 500ms
|
||||
|
||||
// Log pour monitoring
|
||||
System.out.printf("Recherche avancée exécutée en %d ms pour %d résultats%n",
|
||||
executionTime, result.getTotalElements());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(12)
|
||||
@DisplayName("Doit gérer les critères avec caractères spéciaux")
|
||||
void testSearchWithSpecialCharacters() {
|
||||
// Given
|
||||
MembreSearchCriteria criteria = MembreSearchCriteria.builder()
|
||||
.query("marie-josé")
|
||||
.nom("o'connor")
|
||||
.build();
|
||||
|
||||
// When
|
||||
MembreSearchResultDTO result = membreService.searchMembresAdvanced(
|
||||
criteria, Page.of(0, 10), Sort.by("nom"));
|
||||
|
||||
// Then
|
||||
assertThat(result).isNotNull();
|
||||
// La recherche ne doit pas échouer même avec des caractères spéciaux
|
||||
assertThat(result.getTotalElements()).isGreaterThanOrEqualTo(0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user