Initial commit: unionflow-mobile-apps
Application Flutter complète (sans build artifacts). Signed-off-by: lions dev Team
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
package dev.lions.unionflow.server.resource;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
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 java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
/**
|
||||
* 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,392 @@
|
||||
package dev.lions.unionflow.server.service;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
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 dev.lions.unionflow.server.repository.MembreRepository;
|
||||
import dev.lions.unionflow.server.repository.OrganisationRepository;
|
||||
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 java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
@Inject MembreRepository membreRepository;
|
||||
@Inject OrganisationRepository organisationRepository;
|
||||
|
||||
private Organisation testOrganisation;
|
||||
private List<Membre> testMembres;
|
||||
|
||||
@BeforeEach
|
||||
@Transactional
|
||||
void setupTestData() {
|
||||
// Créer et persister une organisation de test
|
||||
testOrganisation =
|
||||
Organisation.builder()
|
||||
.nom("Organisation Test")
|
||||
.typeOrganisation("ASSOCIATION")
|
||||
.statut("ACTIF")
|
||||
.email("test@organisation.com")
|
||||
.build();
|
||||
testOrganisation.setDateCreation(LocalDateTime.now());
|
||||
testOrganisation.setActif(true);
|
||||
organisationRepository.persist(testOrganisation);
|
||||
|
||||
// Créer des membres de test avec différents profils
|
||||
testMembres =
|
||||
List.of(
|
||||
// Membre actif jeune
|
||||
createMembre("UF-2025-TEST001", "Dupont", "Marie", "marie.dupont@test.com",
|
||||
"+221701234567", LocalDate.of(1995, 5, 15), LocalDate.of(2023, 1, 15),
|
||||
"MEMBRE,SECRETAIRE", true),
|
||||
|
||||
// Membre actif âgé
|
||||
createMembre("UF-2025-TEST002", "Martin", "Jean", "jean.martin@test.com",
|
||||
"+221701234568", LocalDate.of(1970, 8, 20), LocalDate.of(2020, 3, 10),
|
||||
"MEMBRE,PRESIDENT", true),
|
||||
|
||||
// Membre inactif
|
||||
createMembre("UF-2025-TEST003", "Diallo", "Fatou", "fatou.diallo@test.com",
|
||||
"+221701234569", LocalDate.of(1985, 12, 3), LocalDate.of(2021, 6, 5),
|
||||
"MEMBRE", false),
|
||||
|
||||
// Membre avec email spécifique
|
||||
createMembre("UF-2025-TEST004", "Sow", "Amadou", "amadou.sow@unionflow.com",
|
||||
"+221701234570", LocalDate.of(1988, 3, 12), LocalDate.of(2022, 9, 20),
|
||||
"MEMBRE,TRESORIER", true));
|
||||
|
||||
// Persister tous les membres
|
||||
testMembres.forEach(membre -> membreRepository.persist(membre));
|
||||
}
|
||||
|
||||
private Membre createMembre(String numero, String nom, String prenom, String email,
|
||||
String telephone, LocalDate dateNaissance, LocalDate dateAdhesion,
|
||||
String roles, boolean actif) {
|
||||
Membre membre = Membre.builder()
|
||||
.numeroMembre(numero)
|
||||
.nom(nom)
|
||||
.prenom(prenom)
|
||||
.email(email)
|
||||
.telephone(telephone)
|
||||
.dateNaissance(dateNaissance)
|
||||
.dateAdhesion(dateAdhesion)
|
||||
.organisation(testOrganisation)
|
||||
.build();
|
||||
membre.setDateCreation(LocalDateTime.now());
|
||||
membre.setActif(actif);
|
||||
// Note: Le champ roles est maintenant List<MembreRole> et doit être géré via la relation MembreRole
|
||||
// Pour les tests, on laisse la liste vide par défaut
|
||||
return membre;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@Transactional
|
||||
void cleanupTestData() {
|
||||
// Nettoyer les données de test
|
||||
if (testMembres != null) {
|
||||
testMembres.forEach(membre -> {
|
||||
if (membre.getId() != null) {
|
||||
membreRepository.delete(membre);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (testOrganisation != null && testOrganisation.getId() != null) {
|
||||
organisationRepository.delete(testOrganisation);
|
||||
}
|
||||
}
|
||||
|
||||
@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