From 317086668f5dad02a2cb82e818f4d409d3ae573f Mon Sep 17 00:00:00 2001 From: Wilfried BRIGITTE Date: Sat, 6 Jun 2026 12:17:10 +0200 Subject: [PATCH 1/2] avis --- .../avis/converter/AvisConverterTest.java | 76 ++++++++ .../dev62/mylibrary/avis/entity/AvisTest.java | 60 ++++++ .../exception/AvisNotFoundExceptionTest.java | 47 +++++ .../exception/NotValidAvisExceptionTest.java | 62 ++++++ .../avis/repository/AvisRepositoryTest.java | 184 ++++++++++++++++++ .../avis/usecase/AvisUseCaseTest.java | 169 ++++++++++++++++ .../avis/validator/AvisValidatorTest.java | 131 +++++++++++++ .../avis/converter/AvisConverterTest.java | 76 ++++++++ .../dev62/mylibrary/avis/entity/AvisTest.java | 60 ++++++ .../exception/AvisNotFoundExceptionTest.java | 47 +++++ .../exception/NotValidAvisExceptionTest.java | 62 ++++++ .../avis/repository/AvisRepositoryTest.java | 184 ++++++++++++++++++ .../avis/usecase/AvisUseCaseTest.java | 169 ++++++++++++++++ .../avis/validator/AvisValidatorTest.java | 131 +++++++++++++ src/test/resources/features/avis.feature | 54 +++++ 15 files changed, 1512 insertions(+) create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java create mode 100644 src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java create mode 100644 src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java create mode 100644 src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java create mode 100644 src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java create mode 100644 src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java create mode 100644 src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java create mode 100644 src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java create mode 100644 src/test/resources/features/avis.feature diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java new file mode 100644 index 0000000..0f8e3ac --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java @@ -0,0 +1,76 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("AvisConverter Unit Tests") +class AvisConverterTest { + + private final UUID clientId = UUID.randomUUID(); + private final UUID livreId = UUID.randomUUID(); + + @Nested + @DisplayName("toDomain() method tests") + class ToDomainTests { + + @Test + @DisplayName("Should convert AvisInfo to Avis domain object") + void shouldConvertAvisInfoToDomain() { + AvisInfo avisInfo = new AvisInfo( + clientId, livreId, 5, "Excellent livre !", LocalDate.of(2024, 1, 15) + ); + + Avis result = AvisConverter.toDomain(avisInfo); + + assertNotNull(result); + assertEquals(clientId, result.getClientId()); + assertEquals(livreId, result.getLivreId()); + assertEquals(5, result.getNote()); + assertEquals("Excellent livre !", result.getCommentaire()); + assertEquals(LocalDate.of(2024, 1, 15), result.getDateAchat()); + } + + @Test + @DisplayName("Should have null ID after toDomain (set by repository)") + void shouldHaveNullIdAfterToDomain() { + AvisInfo avisInfo = new AvisInfo(clientId, livreId, 3, "Commentaire", LocalDate.now()); + + Avis result = AvisConverter.toDomain(avisInfo); + + assertNull(result.getId()); + } + } + + @Nested + @DisplayName("toDTO() method tests") + class ToDTOTests { + + @Test + @DisplayName("Should convert Avis domain object to AvisDTO") + void shouldConvertAvisToDTO() { + UUID avisId = UUID.randomUUID(); + Avis avis = Avis.builder() + .id(avisId) + .clientId(clientId) + .livreId(livreId) + .note(5) + .commentaire("Excellent !") + .dateAchat(LocalDate.of(2024, 1, 15)) + .build(); + + AvisDTO result = AvisConverter.toDTO(avis); + + assertNotNull(result); + assertEquals(avisId, result.getAvisId()); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java new file mode 100644 index 0000000..832fc99 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java @@ -0,0 +1,60 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.entity; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +class AvisTest { + + @Test + @DisplayName("Builder should create a valid Avis instance") + void testAvisBuilder() { + UUID id = UUID.randomUUID(); + UUID clientId = UUID.randomUUID(); + UUID livreId = UUID.randomUUID(); + + Avis avis = Avis.builder() + .id(id) + .clientId(clientId) + .livreId(livreId) + .note(5) + .commentaire("Excellent livre !") + .dateAchat(LocalDate.of(2024, 1, 15)) + .build(); + + assertEquals(id, avis.getId()); + assertEquals(clientId, avis.getClientId()); + assertEquals(livreId, avis.getLivreId()); + assertEquals(5, avis.getNote()); + assertEquals("Excellent livre !", avis.getCommentaire()); + assertEquals(LocalDate.of(2024, 1, 15), avis.getDateAchat()); + } + + @Test + @DisplayName("setRandomUUID should set a new non-null UUID") + void testSetRandomUUID() { + Avis avis = Avis.builder().build(); + UUID originalId = avis.getId(); + + avis.setRandomUUID(); + + assertNotNull(avis.getId()); + assertNotEquals(originalId, avis.getId()); + } + + @Test + @DisplayName("Two setRandomUUID calls should produce different UUIDs") + void testSetRandomUUIDTwice() { + Avis avis = Avis.builder().build(); + avis.setRandomUUID(); + UUID firstId = avis.getId(); + + avis.setRandomUUID(); + + assertNotEquals(firstId, avis.getId()); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java new file mode 100644 index 0000000..aa70cb3 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java @@ -0,0 +1,47 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class AvisNotFoundExceptionTest { + + @Test + @DisplayName("Exception message should contain the UUID provided") + void testExceptionMessageContainsUUID() { + UUID uuid = UUID.randomUUID(); + + AvisNotFoundException exception = new AvisNotFoundException(uuid); + + String expectedMessage = String.format("The avis with id %s does not exist", uuid); + assertEquals(expectedMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should use the correct constant message format") + void testExceptionUsesConstantMessageFormat() { + UUID uuid = UUID.randomUUID(); + + AvisNotFoundException exception = new AvisNotFoundException(uuid); + + assertEquals("The avis with id {0} does not exist", + AvisNotFoundException.THE_AVIS_WITH_ID_DOES_NOT_EXIST_MESSAGE); + assertTrue(exception.getMessage().contains(uuid.toString())); + } + + @Test + @DisplayName("Exception should be properly thrown and caught") + void testExceptionCanBeThrownAndCaught() { + UUID uuid = UUID.randomUUID(); + + try { + throw new AvisNotFoundException(uuid); + } catch (AvisNotFoundException e) { + assertTrue(e.getMessage().contains(uuid.toString())); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java new file mode 100644 index 0000000..768db03 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java @@ -0,0 +1,62 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class NotValidAvisExceptionTest { + + @Test + @DisplayName("Exception should be created with the provided message") + void testExceptionCreation() { + String errorMessage = "Note must be between 1 and 5"; + + NotValidAvisException exception = new NotValidAvisException(errorMessage); + + assertEquals(errorMessage, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = { + "Note must be between 1 and 5", + "Commentaire cannot be blank", + "Client id cannot be null", + "Livre id cannot be null", + "Date achat cannot be null" + }) + @DisplayName("Exception should handle different validation messages") + void testExceptionWithDifferentMessages(String errorMessage) { + NotValidAvisException exception = new NotValidAvisException(errorMessage); + + assertEquals(errorMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should be properly thrown and caught") + void testExceptionCanBeThrownAndCaught() { + String errorMessage = "Note must be between 1 and 5"; + + Exception exception = assertThrows(NotValidAvisException.class, () -> { + throw new NotValidAvisException(errorMessage); + }); + + assertEquals(errorMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should be catchable as a general Exception") + void testExceptionInheritance() { + String errorMessage = "Commentaire cannot be blank"; + + try { + throw new NotValidAvisException(errorMessage); + } catch (Exception e) { + assertEquals(NotValidAvisException.class, e.getClass()); + assertEquals(errorMessage, e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java new file mode 100644 index 0000000..3cda2be --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java @@ -0,0 +1,184 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +class AvisRepositoryTest { + + private AvisRepository repository; + private Avis avis1; + private Avis avis2; + private UUID clientId1; + private UUID livreId1; + + @BeforeEach + void setUp() { + repository = new AvisRepository(); + clientId1 = UUID.randomUUID(); + livreId1 = UUID.randomUUID(); + + avis1 = Avis.builder() + .clientId(clientId1) + .livreId(livreId1) + .note(5) + .commentaire("Excellent livre !") + .dateAchat(LocalDate.of(2024, 1, 15)) + .build(); + avis1.setRandomUUID(); + + avis2 = Avis.builder() + .clientId(UUID.randomUUID()) + .livreId(livreId1) + .note(3) + .commentaire("Pas mal") + .dateAchat(LocalDate.of(2024, 2, 10)) + .build(); + avis2.setRandomUUID(); + } + + @Test + @DisplayName("New repository should be empty") + void testNewRepositoryIsEmpty() { + assertTrue(repository.findAll().isEmpty()); + } + + @Nested + @DisplayName("Save operations") + class SaveOperations { + + @Test + @DisplayName("Save should add a new avis") + void testSaveNewAvis() { + Avis saved = repository.save(avis1); + + assertEquals(1, repository.findAll().size()); + assertEquals(avis1.getId(), saved.getId()); + } + + @Test + @DisplayName("Save should update existing avis with same ID") + void testSaveUpdatesExistingAvis() { + repository.save(avis1); + UUID id = avis1.getId(); + + Avis updated = Avis.builder() + .id(id) + .clientId(clientId1) + .livreId(livreId1) + .note(3) + .commentaire("Finalement moyen") + .dateAchat(LocalDate.of(2024, 1, 15)) + .build(); + + Avis saved = repository.save(updated); + + assertEquals(1, repository.findAll().size()); + assertEquals(id, saved.getId()); + assertEquals(3, saved.getNote()); + } + + @Test + @DisplayName("Save multiple avis should add all of them") + void testSaveMultipleAvis() { + repository.save(avis1); + repository.save(avis2); + + assertEquals(2, repository.findAll().size()); + } + } + + @Nested + @DisplayName("Find operations") + class FindOperations { + + @BeforeEach + void setUpAvis() { + repository.save(avis1); + repository.save(avis2); + } + + @Test + @DisplayName("FindById should return avis with matching ID") + void testFindById() { + Optional found = repository.findById(avis1.getId()); + + assertTrue(found.isPresent()); + assertEquals(avis1.getId(), found.get().getId()); + } + + @Test + @DisplayName("FindById should return empty Optional when ID doesn't exist") + void testFindByIdNotFound() { + Optional found = repository.findById(UUID.randomUUID()); + + assertTrue(found.isEmpty()); + } + + @Test + @DisplayName("FindByLivreId should return all avis for a book") + void testFindByLivreId() { + List found = repository.findByLivreId(livreId1); + + assertEquals(2, found.size()); + } + + @Test + @DisplayName("FindByClientId should return all avis for a client") + void testFindByClientId() { + List found = repository.findByClientId(clientId1); + + assertEquals(1, found.size()); + assertEquals(avis1.getId(), found.getFirst().getId()); + } + + @Test + @DisplayName("ExistsById should return true when ID exists") + void testExistsByIdExists() { + assertTrue(repository.existsById(avis1.getId())); + } + + @Test + @DisplayName("ExistsById should return false when ID doesn't exist") + void testExistsByIdNotExists() { + assertFalse(repository.existsById(UUID.randomUUID())); + } + } + + @Nested + @DisplayName("Delete operations") + class DeleteOperations { + + @BeforeEach + void setUpAvis() { + repository.save(avis1); + repository.save(avis2); + } + + @Test + @DisplayName("Delete should remove the specified avis") + void testDelete() { + repository.delete(avis1); + + assertEquals(1, repository.findAll().size()); + assertFalse(repository.findAll().contains(avis1)); + } + + @Test + @DisplayName("DeleteAll should remove all avis") + void testDeleteAll() { + repository.deleteAll(); + + assertTrue(repository.findAll().isEmpty()); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java new file mode 100644 index 0000000..82d78c3 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java @@ -0,0 +1,169 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.repository.AvisRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.LocalDate; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class AvisUseCaseTest { + + @Mock + private AvisRepository avisRepository; + + @Mock + private CustomerRepository customerRepository; + + @InjectMocks + private AvisUseCase avisUseCase; + + private UUID clientId; + private UUID livreId; + private Customer testCustomer; + private AvisInfo validAvisInfo; + + @BeforeEach + void setUp() { + clientId = UUID.randomUUID(); + livreId = UUID.randomUUID(); + + testCustomer = Customer.builder() + .id(clientId) + .firstName("Marie") + .lastName("Dupont") + .phoneNumber("0612345678") + .loyaltyPoints(100) + .build(); + + validAvisInfo = new AvisInfo(clientId, livreId, 5, "Excellent livre !", LocalDate.of(2024, 1, 15)); + } + + @Nested + @DisplayName("GererAvis tests") + class GererAvisTests { + + @Test + @DisplayName("Should create avis when valid data is provided") + void testGererAvisWithValidData() throws NotValidAvisException, CustomerNotFoundException { + when(customerRepository.findById(clientId)).thenReturn(Optional.of(testCustomer)); + + UUID avisId = UUID.randomUUID(); + Avis savedAvis = Avis.builder() + .id(avisId) + .clientId(clientId) + .livreId(livreId) + .note(5) + .commentaire("Excellent livre !") + .dateAchat(LocalDate.of(2024, 1, 15)) + .build(); + when(avisRepository.save(any(Avis.class))).thenReturn(savedAvis); + + AvisDTO result = avisUseCase.gererAvis(validAvisInfo); + + assertNotNull(result); + assertEquals(avisId, result.getAvisId()); + verify(avisRepository, times(1)).save(any(Avis.class)); + } + + @Test + @DisplayName("Should throw exception when customer does not exist") + void testGererAvisWithUnknownCustomer() { + when(customerRepository.findById(clientId)).thenReturn(Optional.empty()); + + assertThrows(CustomerNotFoundException.class, + () -> avisUseCase.gererAvis(validAvisInfo)); + + verify(avisRepository, never()).save(any(Avis.class)); + } + + @Test + @DisplayName("Should throw exception when note is invalid") + void testGererAvisWithInvalidNote() { + AvisInfo invalidAvis = new AvisInfo(clientId, livreId, 6, "Commentaire", LocalDate.now()); + + assertThrows(NotValidAvisException.class, + () -> avisUseCase.gererAvis(invalidAvis)); + + verify(avisRepository, never()).save(any(Avis.class)); + } + + @Test + @DisplayName("Should throw exception when commentaire is blank") + void testGererAvisWithBlankCommentaire() { + AvisInfo invalidAvis = new AvisInfo(clientId, livreId, 5, "", LocalDate.now()); + + assertThrows(NotValidAvisException.class, + () -> avisUseCase.gererAvis(invalidAvis)); + + verify(avisRepository, never()).save(any(Avis.class)); + } + + @Test + @DisplayName("Should throw exception when clientId is null") + void testGererAvisWithNullClientId() { + AvisInfo invalidAvis = new AvisInfo(null, livreId, 5, "Commentaire", LocalDate.now()); + + assertThrows(NotValidAvisException.class, + () -> avisUseCase.gererAvis(invalidAvis)); + + verify(avisRepository, never()).save(any(Avis.class)); + } + } + + @Nested + @DisplayName("FindAvis tests") + class FindAvisTests { + + @Test + @DisplayName("Should return avis when ID exists") + void testFindAvisById() { + UUID avisId = UUID.randomUUID(); + Avis avis = Avis.builder() + .id(avisId) + .clientId(clientId) + .livreId(livreId) + .note(5) + .commentaire("Excellent !") + .dateAchat(LocalDate.now()) + .build(); + + when(avisRepository.findById(avisId)).thenReturn(Optional.of(avis)); + + Optional result = avisUseCase.findAvisById(avisId); + + assertTrue(result.isPresent()); + assertEquals(avisId, result.get().getAvisId()); + } + + @Test + @DisplayName("Should return empty Optional when ID does not exist") + void testFindAvisByIdNotFound() { + UUID nonExistentId = UUID.randomUUID(); + when(avisRepository.findById(nonExistentId)).thenReturn(Optional.empty()); + + Optional result = avisUseCase.findAvisById(nonExistentId); + + assertTrue(result.isEmpty()); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java new file mode 100644 index 0000000..3fee128 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java @@ -0,0 +1,131 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.time.LocalDate; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +class AvisValidatorTest { + + private final UUID clientId = UUID.randomUUID(); + private final UUID livreId = UUID.randomUUID(); + + private AvisInfo validAvis() { + return new AvisInfo(clientId, livreId, 5, "Excellent livre !", LocalDate.of(2024, 1, 15)); + } + + @Test + @DisplayName("Should validate avis with valid data") + void testValidateValidAvis() { + assertDoesNotThrow(() -> AvisValidator.validate(validAvis())); + } + + @Nested + @DisplayName("ClientId validation tests") + class ClientIdValidationTests { + + @Test + @DisplayName("Should throw exception when clientId is null") + void testValidateNullClientId() { + AvisInfo avis = new AvisInfo(null, livreId, 5, "Commentaire", LocalDate.now()); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.CLIENT_ID_CANNOT_BE_NULL, exception.getMessage()); + } + } + + @Nested + @DisplayName("LivreId validation tests") + class LivreIdValidationTests { + + @Test + @DisplayName("Should throw exception when livreId is null") + void testValidateNullLivreId() { + AvisInfo avis = new AvisInfo(clientId, null, 5, "Commentaire", LocalDate.now()); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.LIVRE_ID_CANNOT_BE_NULL, exception.getMessage()); + } + } + + @Nested + @DisplayName("Note validation tests") + class NoteValidationTests { + + @ParameterizedTest + @ValueSource(ints = {1, 2, 3, 4, 5}) + @DisplayName("Should validate when note is between 1 and 5") + void testValidateValidNote(int validNote) { + AvisInfo avis = new AvisInfo(clientId, livreId, validNote, "Commentaire", LocalDate.now()); + assertDoesNotThrow(() -> AvisValidator.validate(avis)); + } + + @ParameterizedTest + @ValueSource(ints = {0, -1, 6, 10}) + @DisplayName("Should throw exception when note is out of range") + void testValidateInvalidNote(int invalidNote) { + AvisInfo avis = new AvisInfo(clientId, livreId, invalidNote, "Commentaire", LocalDate.now()); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.NOTE_MUST_BE_BETWEEN_1_AND_5, exception.getMessage()); + } + } + + @Nested + @DisplayName("Commentaire validation tests") + class CommentaireValidationTests { + + @Test + @DisplayName("Should throw exception when commentaire is blank") + void testValidateBlankCommentaire() { + AvisInfo avis = new AvisInfo(clientId, livreId, 5, "", LocalDate.now()); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.COMMENTAIRE_CANNOT_BE_BLANK, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = {" ", " ", "\t", "\n"}) + @DisplayName("Should throw exception when commentaire contains only whitespace") + void testValidateWhitespaceCommentaire(String whitespace) { + AvisInfo avis = new AvisInfo(clientId, livreId, 5, whitespace, LocalDate.now()); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.COMMENTAIRE_CANNOT_BE_BLANK, exception.getMessage()); + } + } + + @Nested + @DisplayName("DateAchat validation tests") + class DateAchatValidationTests { + + @Test + @DisplayName("Should throw exception when dateAchat is null") + void testValidateNullDateAchat() { + AvisInfo avis = new AvisInfo(clientId, livreId, 5, "Commentaire", null); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.DATE_ACHAT_CANNOT_BE_NULL, exception.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java new file mode 100644 index 0000000..0f8e3ac --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java @@ -0,0 +1,76 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +@DisplayName("AvisConverter Unit Tests") +class AvisConverterTest { + + private final UUID clientId = UUID.randomUUID(); + private final UUID livreId = UUID.randomUUID(); + + @Nested + @DisplayName("toDomain() method tests") + class ToDomainTests { + + @Test + @DisplayName("Should convert AvisInfo to Avis domain object") + void shouldConvertAvisInfoToDomain() { + AvisInfo avisInfo = new AvisInfo( + clientId, livreId, 5, "Excellent livre !", LocalDate.of(2024, 1, 15) + ); + + Avis result = AvisConverter.toDomain(avisInfo); + + assertNotNull(result); + assertEquals(clientId, result.getClientId()); + assertEquals(livreId, result.getLivreId()); + assertEquals(5, result.getNote()); + assertEquals("Excellent livre !", result.getCommentaire()); + assertEquals(LocalDate.of(2024, 1, 15), result.getDateAchat()); + } + + @Test + @DisplayName("Should have null ID after toDomain (set by repository)") + void shouldHaveNullIdAfterToDomain() { + AvisInfo avisInfo = new AvisInfo(clientId, livreId, 3, "Commentaire", LocalDate.now()); + + Avis result = AvisConverter.toDomain(avisInfo); + + assertNull(result.getId()); + } + } + + @Nested + @DisplayName("toDTO() method tests") + class ToDTOTests { + + @Test + @DisplayName("Should convert Avis domain object to AvisDTO") + void shouldConvertAvisToDTO() { + UUID avisId = UUID.randomUUID(); + Avis avis = Avis.builder() + .id(avisId) + .clientId(clientId) + .livreId(livreId) + .note(5) + .commentaire("Excellent !") + .dateAchat(LocalDate.of(2024, 1, 15)) + .build(); + + AvisDTO result = AvisConverter.toDTO(avis); + + assertNotNull(result); + assertEquals(avisId, result.getAvisId()); + } + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java new file mode 100644 index 0000000..832fc99 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java @@ -0,0 +1,60 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.entity; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +class AvisTest { + + @Test + @DisplayName("Builder should create a valid Avis instance") + void testAvisBuilder() { + UUID id = UUID.randomUUID(); + UUID clientId = UUID.randomUUID(); + UUID livreId = UUID.randomUUID(); + + Avis avis = Avis.builder() + .id(id) + .clientId(clientId) + .livreId(livreId) + .note(5) + .commentaire("Excellent livre !") + .dateAchat(LocalDate.of(2024, 1, 15)) + .build(); + + assertEquals(id, avis.getId()); + assertEquals(clientId, avis.getClientId()); + assertEquals(livreId, avis.getLivreId()); + assertEquals(5, avis.getNote()); + assertEquals("Excellent livre !", avis.getCommentaire()); + assertEquals(LocalDate.of(2024, 1, 15), avis.getDateAchat()); + } + + @Test + @DisplayName("setRandomUUID should set a new non-null UUID") + void testSetRandomUUID() { + Avis avis = Avis.builder().build(); + UUID originalId = avis.getId(); + + avis.setRandomUUID(); + + assertNotNull(avis.getId()); + assertNotEquals(originalId, avis.getId()); + } + + @Test + @DisplayName("Two setRandomUUID calls should produce different UUIDs") + void testSetRandomUUIDTwice() { + Avis avis = Avis.builder().build(); + avis.setRandomUUID(); + UUID firstId = avis.getId(); + + avis.setRandomUUID(); + + assertNotEquals(firstId, avis.getId()); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java new file mode 100644 index 0000000..aa70cb3 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java @@ -0,0 +1,47 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class AvisNotFoundExceptionTest { + + @Test + @DisplayName("Exception message should contain the UUID provided") + void testExceptionMessageContainsUUID() { + UUID uuid = UUID.randomUUID(); + + AvisNotFoundException exception = new AvisNotFoundException(uuid); + + String expectedMessage = String.format("The avis with id %s does not exist", uuid); + assertEquals(expectedMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should use the correct constant message format") + void testExceptionUsesConstantMessageFormat() { + UUID uuid = UUID.randomUUID(); + + AvisNotFoundException exception = new AvisNotFoundException(uuid); + + assertEquals("The avis with id {0} does not exist", + AvisNotFoundException.THE_AVIS_WITH_ID_DOES_NOT_EXIST_MESSAGE); + assertTrue(exception.getMessage().contains(uuid.toString())); + } + + @Test + @DisplayName("Exception should be properly thrown and caught") + void testExceptionCanBeThrownAndCaught() { + UUID uuid = UUID.randomUUID(); + + try { + throw new AvisNotFoundException(uuid); + } catch (AvisNotFoundException e) { + assertTrue(e.getMessage().contains(uuid.toString())); + } + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java new file mode 100644 index 0000000..768db03 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java @@ -0,0 +1,62 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class NotValidAvisExceptionTest { + + @Test + @DisplayName("Exception should be created with the provided message") + void testExceptionCreation() { + String errorMessage = "Note must be between 1 and 5"; + + NotValidAvisException exception = new NotValidAvisException(errorMessage); + + assertEquals(errorMessage, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = { + "Note must be between 1 and 5", + "Commentaire cannot be blank", + "Client id cannot be null", + "Livre id cannot be null", + "Date achat cannot be null" + }) + @DisplayName("Exception should handle different validation messages") + void testExceptionWithDifferentMessages(String errorMessage) { + NotValidAvisException exception = new NotValidAvisException(errorMessage); + + assertEquals(errorMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should be properly thrown and caught") + void testExceptionCanBeThrownAndCaught() { + String errorMessage = "Note must be between 1 and 5"; + + Exception exception = assertThrows(NotValidAvisException.class, () -> { + throw new NotValidAvisException(errorMessage); + }); + + assertEquals(errorMessage, exception.getMessage()); + } + + @Test + @DisplayName("Exception should be catchable as a general Exception") + void testExceptionInheritance() { + String errorMessage = "Commentaire cannot be blank"; + + try { + throw new NotValidAvisException(errorMessage); + } catch (Exception e) { + assertEquals(NotValidAvisException.class, e.getClass()); + assertEquals(errorMessage, e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java new file mode 100644 index 0000000..3cda2be --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java @@ -0,0 +1,184 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +class AvisRepositoryTest { + + private AvisRepository repository; + private Avis avis1; + private Avis avis2; + private UUID clientId1; + private UUID livreId1; + + @BeforeEach + void setUp() { + repository = new AvisRepository(); + clientId1 = UUID.randomUUID(); + livreId1 = UUID.randomUUID(); + + avis1 = Avis.builder() + .clientId(clientId1) + .livreId(livreId1) + .note(5) + .commentaire("Excellent livre !") + .dateAchat(LocalDate.of(2024, 1, 15)) + .build(); + avis1.setRandomUUID(); + + avis2 = Avis.builder() + .clientId(UUID.randomUUID()) + .livreId(livreId1) + .note(3) + .commentaire("Pas mal") + .dateAchat(LocalDate.of(2024, 2, 10)) + .build(); + avis2.setRandomUUID(); + } + + @Test + @DisplayName("New repository should be empty") + void testNewRepositoryIsEmpty() { + assertTrue(repository.findAll().isEmpty()); + } + + @Nested + @DisplayName("Save operations") + class SaveOperations { + + @Test + @DisplayName("Save should add a new avis") + void testSaveNewAvis() { + Avis saved = repository.save(avis1); + + assertEquals(1, repository.findAll().size()); + assertEquals(avis1.getId(), saved.getId()); + } + + @Test + @DisplayName("Save should update existing avis with same ID") + void testSaveUpdatesExistingAvis() { + repository.save(avis1); + UUID id = avis1.getId(); + + Avis updated = Avis.builder() + .id(id) + .clientId(clientId1) + .livreId(livreId1) + .note(3) + .commentaire("Finalement moyen") + .dateAchat(LocalDate.of(2024, 1, 15)) + .build(); + + Avis saved = repository.save(updated); + + assertEquals(1, repository.findAll().size()); + assertEquals(id, saved.getId()); + assertEquals(3, saved.getNote()); + } + + @Test + @DisplayName("Save multiple avis should add all of them") + void testSaveMultipleAvis() { + repository.save(avis1); + repository.save(avis2); + + assertEquals(2, repository.findAll().size()); + } + } + + @Nested + @DisplayName("Find operations") + class FindOperations { + + @BeforeEach + void setUpAvis() { + repository.save(avis1); + repository.save(avis2); + } + + @Test + @DisplayName("FindById should return avis with matching ID") + void testFindById() { + Optional found = repository.findById(avis1.getId()); + + assertTrue(found.isPresent()); + assertEquals(avis1.getId(), found.get().getId()); + } + + @Test + @DisplayName("FindById should return empty Optional when ID doesn't exist") + void testFindByIdNotFound() { + Optional found = repository.findById(UUID.randomUUID()); + + assertTrue(found.isEmpty()); + } + + @Test + @DisplayName("FindByLivreId should return all avis for a book") + void testFindByLivreId() { + List found = repository.findByLivreId(livreId1); + + assertEquals(2, found.size()); + } + + @Test + @DisplayName("FindByClientId should return all avis for a client") + void testFindByClientId() { + List found = repository.findByClientId(clientId1); + + assertEquals(1, found.size()); + assertEquals(avis1.getId(), found.getFirst().getId()); + } + + @Test + @DisplayName("ExistsById should return true when ID exists") + void testExistsByIdExists() { + assertTrue(repository.existsById(avis1.getId())); + } + + @Test + @DisplayName("ExistsById should return false when ID doesn't exist") + void testExistsByIdNotExists() { + assertFalse(repository.existsById(UUID.randomUUID())); + } + } + + @Nested + @DisplayName("Delete operations") + class DeleteOperations { + + @BeforeEach + void setUpAvis() { + repository.save(avis1); + repository.save(avis2); + } + + @Test + @DisplayName("Delete should remove the specified avis") + void testDelete() { + repository.delete(avis1); + + assertEquals(1, repository.findAll().size()); + assertFalse(repository.findAll().contains(avis1)); + } + + @Test + @DisplayName("DeleteAll should remove all avis") + void testDeleteAll() { + repository.deleteAll(); + + assertTrue(repository.findAll().isEmpty()); + } + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java new file mode 100644 index 0000000..82d78c3 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java @@ -0,0 +1,169 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.repository.AvisRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.time.LocalDate; +import java.util.Optional; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class AvisUseCaseTest { + + @Mock + private AvisRepository avisRepository; + + @Mock + private CustomerRepository customerRepository; + + @InjectMocks + private AvisUseCase avisUseCase; + + private UUID clientId; + private UUID livreId; + private Customer testCustomer; + private AvisInfo validAvisInfo; + + @BeforeEach + void setUp() { + clientId = UUID.randomUUID(); + livreId = UUID.randomUUID(); + + testCustomer = Customer.builder() + .id(clientId) + .firstName("Marie") + .lastName("Dupont") + .phoneNumber("0612345678") + .loyaltyPoints(100) + .build(); + + validAvisInfo = new AvisInfo(clientId, livreId, 5, "Excellent livre !", LocalDate.of(2024, 1, 15)); + } + + @Nested + @DisplayName("GererAvis tests") + class GererAvisTests { + + @Test + @DisplayName("Should create avis when valid data is provided") + void testGererAvisWithValidData() throws NotValidAvisException, CustomerNotFoundException { + when(customerRepository.findById(clientId)).thenReturn(Optional.of(testCustomer)); + + UUID avisId = UUID.randomUUID(); + Avis savedAvis = Avis.builder() + .id(avisId) + .clientId(clientId) + .livreId(livreId) + .note(5) + .commentaire("Excellent livre !") + .dateAchat(LocalDate.of(2024, 1, 15)) + .build(); + when(avisRepository.save(any(Avis.class))).thenReturn(savedAvis); + + AvisDTO result = avisUseCase.gererAvis(validAvisInfo); + + assertNotNull(result); + assertEquals(avisId, result.getAvisId()); + verify(avisRepository, times(1)).save(any(Avis.class)); + } + + @Test + @DisplayName("Should throw exception when customer does not exist") + void testGererAvisWithUnknownCustomer() { + when(customerRepository.findById(clientId)).thenReturn(Optional.empty()); + + assertThrows(CustomerNotFoundException.class, + () -> avisUseCase.gererAvis(validAvisInfo)); + + verify(avisRepository, never()).save(any(Avis.class)); + } + + @Test + @DisplayName("Should throw exception when note is invalid") + void testGererAvisWithInvalidNote() { + AvisInfo invalidAvis = new AvisInfo(clientId, livreId, 6, "Commentaire", LocalDate.now()); + + assertThrows(NotValidAvisException.class, + () -> avisUseCase.gererAvis(invalidAvis)); + + verify(avisRepository, never()).save(any(Avis.class)); + } + + @Test + @DisplayName("Should throw exception when commentaire is blank") + void testGererAvisWithBlankCommentaire() { + AvisInfo invalidAvis = new AvisInfo(clientId, livreId, 5, "", LocalDate.now()); + + assertThrows(NotValidAvisException.class, + () -> avisUseCase.gererAvis(invalidAvis)); + + verify(avisRepository, never()).save(any(Avis.class)); + } + + @Test + @DisplayName("Should throw exception when clientId is null") + void testGererAvisWithNullClientId() { + AvisInfo invalidAvis = new AvisInfo(null, livreId, 5, "Commentaire", LocalDate.now()); + + assertThrows(NotValidAvisException.class, + () -> avisUseCase.gererAvis(invalidAvis)); + + verify(avisRepository, never()).save(any(Avis.class)); + } + } + + @Nested + @DisplayName("FindAvis tests") + class FindAvisTests { + + @Test + @DisplayName("Should return avis when ID exists") + void testFindAvisById() { + UUID avisId = UUID.randomUUID(); + Avis avis = Avis.builder() + .id(avisId) + .clientId(clientId) + .livreId(livreId) + .note(5) + .commentaire("Excellent !") + .dateAchat(LocalDate.now()) + .build(); + + when(avisRepository.findById(avisId)).thenReturn(Optional.of(avis)); + + Optional result = avisUseCase.findAvisById(avisId); + + assertTrue(result.isPresent()); + assertEquals(avisId, result.get().getAvisId()); + } + + @Test + @DisplayName("Should return empty Optional when ID does not exist") + void testFindAvisByIdNotFound() { + UUID nonExistentId = UUID.randomUUID(); + when(avisRepository.findById(nonExistentId)).thenReturn(Optional.empty()); + + Optional result = avisUseCase.findAvisById(nonExistentId); + + assertTrue(result.isEmpty()); + } + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java new file mode 100644 index 0000000..3fee128 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java @@ -0,0 +1,131 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.time.LocalDate; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +class AvisValidatorTest { + + private final UUID clientId = UUID.randomUUID(); + private final UUID livreId = UUID.randomUUID(); + + private AvisInfo validAvis() { + return new AvisInfo(clientId, livreId, 5, "Excellent livre !", LocalDate.of(2024, 1, 15)); + } + + @Test + @DisplayName("Should validate avis with valid data") + void testValidateValidAvis() { + assertDoesNotThrow(() -> AvisValidator.validate(validAvis())); + } + + @Nested + @DisplayName("ClientId validation tests") + class ClientIdValidationTests { + + @Test + @DisplayName("Should throw exception when clientId is null") + void testValidateNullClientId() { + AvisInfo avis = new AvisInfo(null, livreId, 5, "Commentaire", LocalDate.now()); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.CLIENT_ID_CANNOT_BE_NULL, exception.getMessage()); + } + } + + @Nested + @DisplayName("LivreId validation tests") + class LivreIdValidationTests { + + @Test + @DisplayName("Should throw exception when livreId is null") + void testValidateNullLivreId() { + AvisInfo avis = new AvisInfo(clientId, null, 5, "Commentaire", LocalDate.now()); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.LIVRE_ID_CANNOT_BE_NULL, exception.getMessage()); + } + } + + @Nested + @DisplayName("Note validation tests") + class NoteValidationTests { + + @ParameterizedTest + @ValueSource(ints = {1, 2, 3, 4, 5}) + @DisplayName("Should validate when note is between 1 and 5") + void testValidateValidNote(int validNote) { + AvisInfo avis = new AvisInfo(clientId, livreId, validNote, "Commentaire", LocalDate.now()); + assertDoesNotThrow(() -> AvisValidator.validate(avis)); + } + + @ParameterizedTest + @ValueSource(ints = {0, -1, 6, 10}) + @DisplayName("Should throw exception when note is out of range") + void testValidateInvalidNote(int invalidNote) { + AvisInfo avis = new AvisInfo(clientId, livreId, invalidNote, "Commentaire", LocalDate.now()); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.NOTE_MUST_BE_BETWEEN_1_AND_5, exception.getMessage()); + } + } + + @Nested + @DisplayName("Commentaire validation tests") + class CommentaireValidationTests { + + @Test + @DisplayName("Should throw exception when commentaire is blank") + void testValidateBlankCommentaire() { + AvisInfo avis = new AvisInfo(clientId, livreId, 5, "", LocalDate.now()); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.COMMENTAIRE_CANNOT_BE_BLANK, exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = {" ", " ", "\t", "\n"}) + @DisplayName("Should throw exception when commentaire contains only whitespace") + void testValidateWhitespaceCommentaire(String whitespace) { + AvisInfo avis = new AvisInfo(clientId, livreId, 5, whitespace, LocalDate.now()); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.COMMENTAIRE_CANNOT_BE_BLANK, exception.getMessage()); + } + } + + @Nested + @DisplayName("DateAchat validation tests") + class DateAchatValidationTests { + + @Test + @DisplayName("Should throw exception when dateAchat is null") + void testValidateNullDateAchat() { + AvisInfo avis = new AvisInfo(clientId, livreId, 5, "Commentaire", null); + + NotValidAvisException exception = assertThrows(NotValidAvisException.class, + () -> AvisValidator.validate(avis)); + + assertEquals(AvisValidator.DATE_ACHAT_CANNOT_BE_NULL, exception.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/test/resources/features/avis.feature b/src/test/resources/features/avis.feature new file mode 100644 index 0000000..24e6950 --- /dev/null +++ b/src/test/resources/features/avis.feature @@ -0,0 +1,54 @@ +# language: en + +Feature: Manage customer reviews + + Background: + Given the system has the following customers for avis: + | prenom | nom | numeroTelephone | pointsFidelite | + | Marie | Dupont | 0612345678 | 100 | + | Jean | Martin | 0687654321 | 50 | + And the catalog has the following books for avis: + | isbn | titre | auteur | editeur | datePublication | prix | stockInitial | categories | description | langue | + | 9782016289308 | Le Petit Prince | Antoine de Saint-Exupery | Gallimard | 1943-04-06 | 12.90 | 10 | Roman | Un classique | FR | + | 9782070409189 | L Etranger | Albert Camus | Gallimard | 1942-05-19 | 9.50 | 5 | Roman | Philosophique| FR | + + Scenario: Submit a valid review + When customer "0612345678" submits a review for book "9782016289308" with: + | note | commentaire | dateAchat | + | 5 | Excellent livre ! | 2024-01-15 | + Then a new review is created + And the system now has 1 reviews + + Scenario: Submit a review with minimum note + When customer "0687654321" submits a review for book "9782070409189" with: + | note | commentaire | dateAchat | + | 1 | Pas mon style | 2024-02-10 | + Then a new review is created + And the system now has 1 reviews + + Scenario: Attempt to submit a review with invalid note too high + When customer "0612345678" tries to submit a review for book "9782016289308" with: + | note | commentaire | dateAchat | + | 6 | Trop bien ! | 2024-01-15 | + Then the review creation fails + And I receive a validation avis error containing "Note must be between 1 and 5" + + Scenario: Attempt to submit a review with invalid note too low + When customer "0612345678" tries to submit a review for book "9782016289308" with: + | note | commentaire | dateAchat | + | 0 | Nul ! | 2024-01-15 | + Then the review creation fails + And I receive a validation avis error containing "Note must be between 1 and 5" + + Scenario: Attempt to submit a review with blank comment + When customer "0612345678" tries to submit a review for book "9782016289308" with: + | note | commentaire | dateAchat | + | 4 | | 2024-01-15 | + Then the review creation fails + And I receive a validation avis error containing "Commentaire cannot be blank" + + Scenario: Attempt to submit a review for unknown customer + When an unknown customer tries to submit a review for book "9782016289308" with: + | note | commentaire | dateAchat | + | 4 | Bon livre | 2024-01-15 | + Then the review creation fails with customer not found From a392e6bee399c99b6381427619b49ec5c443ab53 Mon Sep 17 00:00:00 2001 From: Wilfried BRIGITTE Date: Sat, 6 Jun 2026 12:37:02 +0200 Subject: [PATCH 2/2] avis suite --- .../but3/dev62/mylibrary/avis/AvisDTO.java | 12 ++ .../but3/dev62/mylibrary/avis/AvisInfo.java | 13 ++ .../avis/converter/AvisConverter.java | 27 +++ .../avis/converter/AvisConverterTest.java | 76 -------- .../dev62/mylibrary/avis/entity/Avis.java | 22 +++ .../dev62/mylibrary/avis/entity/AvisTest.java | 60 ------ .../avis/exception/AvisNotFoundException.java | 13 ++ .../exception/AvisNotFoundExceptionTest.java | 47 ----- .../avis/exception/NotValidAvisException.java | 8 + .../exception/NotValidAvisExceptionTest.java | 62 ------ .../avis/repository/AvisRepository.java | 57 ++++++ .../avis/repository/AvisRepositoryTest.java | 184 ------------------ .../mylibrary/avis/usecase/AvisUseCase.java | 41 ++++ .../avis/usecase/AvisUseCaseTest.java | 169 ---------------- .../avis/validator/AvisValidator.java | 54 +++++ .../avis/validator/AvisValidatorTest.java | 131 ------------- 16 files changed, 247 insertions(+), 729 deletions(-) create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisDTO.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisInfo.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverter.java delete mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/Avis.java delete mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundException.java delete mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisException.java delete mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepository.java delete mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCase.java delete mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java create mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidator.java delete mode 100644 src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisDTO.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisDTO.java new file mode 100644 index 0000000..09dad8f --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisDTO.java @@ -0,0 +1,12 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis; + +import lombok.Builder; +import lombok.Getter; + +import java.util.UUID; + +@Builder +@Getter +public class AvisDTO { + private final UUID avisId; +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisInfo.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisInfo.java new file mode 100644 index 0000000..7175c38 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/AvisInfo.java @@ -0,0 +1,13 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis; + +import java.time.LocalDate; +import java.util.UUID; + +public record AvisInfo( + UUID clientId, + UUID livreId, + int note, + String commentaire, + LocalDate dateAchat +) { +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverter.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverter.java new file mode 100644 index 0000000..5c5d44a --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverter.java @@ -0,0 +1,27 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.converter; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; + +public final class AvisConverter { + + private AvisConverter() { + } + + public static Avis toDomain(AvisInfo avisInfo) { + return Avis.builder() + .clientId(avisInfo.clientId()) + .livreId(avisInfo.livreId()) + .note(avisInfo.note()) + .commentaire(avisInfo.commentaire()) + .dateAchat(avisInfo.dateAchat()) + .build(); + } + + public static AvisDTO toDTO(Avis avis) { + return AvisDTO.builder() + .avisId(avis.getId()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java deleted file mode 100644 index 0f8e3ac..0000000 --- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/converter/AvisConverterTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package fr.iut_fbleau.but3.dev62.mylibrary.avis.converter; - -import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisDTO; -import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; -import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import java.time.LocalDate; -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.*; - -@DisplayName("AvisConverter Unit Tests") -class AvisConverterTest { - - private final UUID clientId = UUID.randomUUID(); - private final UUID livreId = UUID.randomUUID(); - - @Nested - @DisplayName("toDomain() method tests") - class ToDomainTests { - - @Test - @DisplayName("Should convert AvisInfo to Avis domain object") - void shouldConvertAvisInfoToDomain() { - AvisInfo avisInfo = new AvisInfo( - clientId, livreId, 5, "Excellent livre !", LocalDate.of(2024, 1, 15) - ); - - Avis result = AvisConverter.toDomain(avisInfo); - - assertNotNull(result); - assertEquals(clientId, result.getClientId()); - assertEquals(livreId, result.getLivreId()); - assertEquals(5, result.getNote()); - assertEquals("Excellent livre !", result.getCommentaire()); - assertEquals(LocalDate.of(2024, 1, 15), result.getDateAchat()); - } - - @Test - @DisplayName("Should have null ID after toDomain (set by repository)") - void shouldHaveNullIdAfterToDomain() { - AvisInfo avisInfo = new AvisInfo(clientId, livreId, 3, "Commentaire", LocalDate.now()); - - Avis result = AvisConverter.toDomain(avisInfo); - - assertNull(result.getId()); - } - } - - @Nested - @DisplayName("toDTO() method tests") - class ToDTOTests { - - @Test - @DisplayName("Should convert Avis domain object to AvisDTO") - void shouldConvertAvisToDTO() { - UUID avisId = UUID.randomUUID(); - Avis avis = Avis.builder() - .id(avisId) - .clientId(clientId) - .livreId(livreId) - .note(5) - .commentaire("Excellent !") - .dateAchat(LocalDate.of(2024, 1, 15)) - .build(); - - AvisDTO result = AvisConverter.toDTO(avis); - - assertNotNull(result); - assertEquals(avisId, result.getAvisId()); - } - } -} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/Avis.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/Avis.java new file mode 100644 index 0000000..715b5b7 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/Avis.java @@ -0,0 +1,22 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.entity; + +import lombok.Builder; +import lombok.Getter; + +import java.time.LocalDate; +import java.util.UUID; + +@Builder +@Getter +public class Avis { + private UUID id; + private UUID clientId; + private UUID livreId; + private int note; + private String commentaire; + private LocalDate dateAchat; + + public void setRandomUUID() { + this.id = UUID.randomUUID(); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java deleted file mode 100644 index 832fc99..0000000 --- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/entity/AvisTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package fr.iut_fbleau.but3.dev62.mylibrary.avis.entity; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.time.LocalDate; -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.*; - -class AvisTest { - - @Test - @DisplayName("Builder should create a valid Avis instance") - void testAvisBuilder() { - UUID id = UUID.randomUUID(); - UUID clientId = UUID.randomUUID(); - UUID livreId = UUID.randomUUID(); - - Avis avis = Avis.builder() - .id(id) - .clientId(clientId) - .livreId(livreId) - .note(5) - .commentaire("Excellent livre !") - .dateAchat(LocalDate.of(2024, 1, 15)) - .build(); - - assertEquals(id, avis.getId()); - assertEquals(clientId, avis.getClientId()); - assertEquals(livreId, avis.getLivreId()); - assertEquals(5, avis.getNote()); - assertEquals("Excellent livre !", avis.getCommentaire()); - assertEquals(LocalDate.of(2024, 1, 15), avis.getDateAchat()); - } - - @Test - @DisplayName("setRandomUUID should set a new non-null UUID") - void testSetRandomUUID() { - Avis avis = Avis.builder().build(); - UUID originalId = avis.getId(); - - avis.setRandomUUID(); - - assertNotNull(avis.getId()); - assertNotEquals(originalId, avis.getId()); - } - - @Test - @DisplayName("Two setRandomUUID calls should produce different UUIDs") - void testSetRandomUUIDTwice() { - Avis avis = Avis.builder().build(); - avis.setRandomUUID(); - UUID firstId = avis.getId(); - - avis.setRandomUUID(); - - assertNotEquals(firstId, avis.getId()); - } -} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundException.java new file mode 100644 index 0000000..e8e6b00 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundException.java @@ -0,0 +1,13 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; + +import java.text.MessageFormat; +import java.util.UUID; + +public class AvisNotFoundException extends Exception { + + public static final String THE_AVIS_WITH_ID_DOES_NOT_EXIST_MESSAGE = "The avis with id {0} does not exist"; + + public AvisNotFoundException(UUID uuid) { + super(MessageFormat.format(THE_AVIS_WITH_ID_DOES_NOT_EXIST_MESSAGE, uuid)); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java deleted file mode 100644 index aa70cb3..0000000 --- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/AvisNotFoundExceptionTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -class AvisNotFoundExceptionTest { - - @Test - @DisplayName("Exception message should contain the UUID provided") - void testExceptionMessageContainsUUID() { - UUID uuid = UUID.randomUUID(); - - AvisNotFoundException exception = new AvisNotFoundException(uuid); - - String expectedMessage = String.format("The avis with id %s does not exist", uuid); - assertEquals(expectedMessage, exception.getMessage()); - } - - @Test - @DisplayName("Exception should use the correct constant message format") - void testExceptionUsesConstantMessageFormat() { - UUID uuid = UUID.randomUUID(); - - AvisNotFoundException exception = new AvisNotFoundException(uuid); - - assertEquals("The avis with id {0} does not exist", - AvisNotFoundException.THE_AVIS_WITH_ID_DOES_NOT_EXIST_MESSAGE); - assertTrue(exception.getMessage().contains(uuid.toString())); - } - - @Test - @DisplayName("Exception should be properly thrown and caught") - void testExceptionCanBeThrownAndCaught() { - UUID uuid = UUID.randomUUID(); - - try { - throw new AvisNotFoundException(uuid); - } catch (AvisNotFoundException e) { - assertTrue(e.getMessage().contains(uuid.toString())); - } - } -} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisException.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisException.java new file mode 100644 index 0000000..8bde194 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisException.java @@ -0,0 +1,8 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; + +public class NotValidAvisException extends Exception { + + public NotValidAvisException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java deleted file mode 100644 index 768db03..0000000 --- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/exception/NotValidAvisExceptionTest.java +++ /dev/null @@ -1,62 +0,0 @@ -package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class NotValidAvisExceptionTest { - - @Test - @DisplayName("Exception should be created with the provided message") - void testExceptionCreation() { - String errorMessage = "Note must be between 1 and 5"; - - NotValidAvisException exception = new NotValidAvisException(errorMessage); - - assertEquals(errorMessage, exception.getMessage()); - } - - @ParameterizedTest - @ValueSource(strings = { - "Note must be between 1 and 5", - "Commentaire cannot be blank", - "Client id cannot be null", - "Livre id cannot be null", - "Date achat cannot be null" - }) - @DisplayName("Exception should handle different validation messages") - void testExceptionWithDifferentMessages(String errorMessage) { - NotValidAvisException exception = new NotValidAvisException(errorMessage); - - assertEquals(errorMessage, exception.getMessage()); - } - - @Test - @DisplayName("Exception should be properly thrown and caught") - void testExceptionCanBeThrownAndCaught() { - String errorMessage = "Note must be between 1 and 5"; - - Exception exception = assertThrows(NotValidAvisException.class, () -> { - throw new NotValidAvisException(errorMessage); - }); - - assertEquals(errorMessage, exception.getMessage()); - } - - @Test - @DisplayName("Exception should be catchable as a general Exception") - void testExceptionInheritance() { - String errorMessage = "Commentaire cannot be blank"; - - try { - throw new NotValidAvisException(errorMessage); - } catch (Exception e) { - assertEquals(NotValidAvisException.class, e.getClass()); - assertEquals(errorMessage, e.getMessage()); - } - } -} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepository.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepository.java new file mode 100644 index 0000000..d26a933 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepository.java @@ -0,0 +1,57 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.repository; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +@NoArgsConstructor +public final class AvisRepository { + + private final List avisList = new ArrayList<>(); + + public List findAll() { + return avisList; + } + + public void deleteAll() { + avisList.clear(); + } + + public Avis save(Avis newAvis) { + Optional existing = this.findById(newAvis.getId()); + existing.ifPresentOrElse(avisList::remove, newAvis::setRandomUUID); + this.avisList.add(newAvis); + return newAvis; + } + + public Optional findById(UUID uuid) { + return this.avisList.stream() + .filter(avis -> avis.getId().equals(uuid)) + .findFirst(); + } + + public boolean existsById(UUID uuid) { + return this.avisList.stream() + .anyMatch(avis -> avis.getId().equals(uuid)); + } + + public List findByLivreId(UUID livreId) { + return this.avisList.stream() + .filter(avis -> avis.getLivreId().equals(livreId)) + .toList(); + } + + public List findByClientId(UUID clientId) { + return this.avisList.stream() + .filter(avis -> avis.getClientId().equals(clientId)) + .toList(); + } + + public void delete(Avis avis) { + avisList.remove(avis); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java deleted file mode 100644 index 3cda2be..0000000 --- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/repository/AvisRepositoryTest.java +++ /dev/null @@ -1,184 +0,0 @@ -package fr.iut_fbleau.but3.dev62.mylibrary.avis.repository; - -import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; - -import java.time.LocalDate; -import java.util.List; -import java.util.Optional; -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.*; - -class AvisRepositoryTest { - - private AvisRepository repository; - private Avis avis1; - private Avis avis2; - private UUID clientId1; - private UUID livreId1; - - @BeforeEach - void setUp() { - repository = new AvisRepository(); - clientId1 = UUID.randomUUID(); - livreId1 = UUID.randomUUID(); - - avis1 = Avis.builder() - .clientId(clientId1) - .livreId(livreId1) - .note(5) - .commentaire("Excellent livre !") - .dateAchat(LocalDate.of(2024, 1, 15)) - .build(); - avis1.setRandomUUID(); - - avis2 = Avis.builder() - .clientId(UUID.randomUUID()) - .livreId(livreId1) - .note(3) - .commentaire("Pas mal") - .dateAchat(LocalDate.of(2024, 2, 10)) - .build(); - avis2.setRandomUUID(); - } - - @Test - @DisplayName("New repository should be empty") - void testNewRepositoryIsEmpty() { - assertTrue(repository.findAll().isEmpty()); - } - - @Nested - @DisplayName("Save operations") - class SaveOperations { - - @Test - @DisplayName("Save should add a new avis") - void testSaveNewAvis() { - Avis saved = repository.save(avis1); - - assertEquals(1, repository.findAll().size()); - assertEquals(avis1.getId(), saved.getId()); - } - - @Test - @DisplayName("Save should update existing avis with same ID") - void testSaveUpdatesExistingAvis() { - repository.save(avis1); - UUID id = avis1.getId(); - - Avis updated = Avis.builder() - .id(id) - .clientId(clientId1) - .livreId(livreId1) - .note(3) - .commentaire("Finalement moyen") - .dateAchat(LocalDate.of(2024, 1, 15)) - .build(); - - Avis saved = repository.save(updated); - - assertEquals(1, repository.findAll().size()); - assertEquals(id, saved.getId()); - assertEquals(3, saved.getNote()); - } - - @Test - @DisplayName("Save multiple avis should add all of them") - void testSaveMultipleAvis() { - repository.save(avis1); - repository.save(avis2); - - assertEquals(2, repository.findAll().size()); - } - } - - @Nested - @DisplayName("Find operations") - class FindOperations { - - @BeforeEach - void setUpAvis() { - repository.save(avis1); - repository.save(avis2); - } - - @Test - @DisplayName("FindById should return avis with matching ID") - void testFindById() { - Optional found = repository.findById(avis1.getId()); - - assertTrue(found.isPresent()); - assertEquals(avis1.getId(), found.get().getId()); - } - - @Test - @DisplayName("FindById should return empty Optional when ID doesn't exist") - void testFindByIdNotFound() { - Optional found = repository.findById(UUID.randomUUID()); - - assertTrue(found.isEmpty()); - } - - @Test - @DisplayName("FindByLivreId should return all avis for a book") - void testFindByLivreId() { - List found = repository.findByLivreId(livreId1); - - assertEquals(2, found.size()); - } - - @Test - @DisplayName("FindByClientId should return all avis for a client") - void testFindByClientId() { - List found = repository.findByClientId(clientId1); - - assertEquals(1, found.size()); - assertEquals(avis1.getId(), found.getFirst().getId()); - } - - @Test - @DisplayName("ExistsById should return true when ID exists") - void testExistsByIdExists() { - assertTrue(repository.existsById(avis1.getId())); - } - - @Test - @DisplayName("ExistsById should return false when ID doesn't exist") - void testExistsByIdNotExists() { - assertFalse(repository.existsById(UUID.randomUUID())); - } - } - - @Nested - @DisplayName("Delete operations") - class DeleteOperations { - - @BeforeEach - void setUpAvis() { - repository.save(avis1); - repository.save(avis2); - } - - @Test - @DisplayName("Delete should remove the specified avis") - void testDelete() { - repository.delete(avis1); - - assertEquals(1, repository.findAll().size()); - assertFalse(repository.findAll().contains(avis1)); - } - - @Test - @DisplayName("DeleteAll should remove all avis") - void testDeleteAll() { - repository.deleteAll(); - - assertTrue(repository.findAll().isEmpty()); - } - } -} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCase.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCase.java new file mode 100644 index 0000000..0b81ede --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCase.java @@ -0,0 +1,41 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.converter.AvisConverter; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.repository.AvisRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.validator.AvisValidator; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException; +import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository; + +import java.util.Optional; +import java.util.UUID; + +public final class AvisUseCase { + + private final AvisRepository avisRepository; + private final CustomerRepository customerRepository; + + public AvisUseCase(AvisRepository avisRepository, CustomerRepository customerRepository) { + this.avisRepository = avisRepository; + this.customerRepository = customerRepository; + } + + public AvisDTO gererAvis(AvisInfo avisInfo) throws NotValidAvisException, CustomerNotFoundException { + AvisValidator.validate(avisInfo); + + customerRepository.findById(avisInfo.clientId()) + .orElseThrow(() -> new CustomerNotFoundException(avisInfo.clientId())); + + Avis avis = AvisConverter.toDomain(avisInfo); + Avis savedAvis = avisRepository.save(avis); + + return AvisConverter.toDTO(savedAvis); + } + + public Optional findAvisById(UUID uuid) { + return avisRepository.findById(uuid).map(AvisConverter::toDTO); + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java deleted file mode 100644 index 82d78c3..0000000 --- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/usecase/AvisUseCaseTest.java +++ /dev/null @@ -1,169 +0,0 @@ -package fr.iut_fbleau.but3.dev62.mylibrary.avis.usecase; - -import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisDTO; -import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; -import fr.iut_fbleau.but3.dev62.mylibrary.avis.entity.Avis; -import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; -import fr.iut_fbleau.but3.dev62.mylibrary.avis.repository.AvisRepository; -import fr.iut_fbleau.but3.dev62.mylibrary.customer.entity.Customer; -import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.CustomerNotFoundException; -import fr.iut_fbleau.but3.dev62.mylibrary.customer.repository.CustomerRepository; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.time.LocalDate; -import java.util.Optional; -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -@ExtendWith(MockitoExtension.class) -class AvisUseCaseTest { - - @Mock - private AvisRepository avisRepository; - - @Mock - private CustomerRepository customerRepository; - - @InjectMocks - private AvisUseCase avisUseCase; - - private UUID clientId; - private UUID livreId; - private Customer testCustomer; - private AvisInfo validAvisInfo; - - @BeforeEach - void setUp() { - clientId = UUID.randomUUID(); - livreId = UUID.randomUUID(); - - testCustomer = Customer.builder() - .id(clientId) - .firstName("Marie") - .lastName("Dupont") - .phoneNumber("0612345678") - .loyaltyPoints(100) - .build(); - - validAvisInfo = new AvisInfo(clientId, livreId, 5, "Excellent livre !", LocalDate.of(2024, 1, 15)); - } - - @Nested - @DisplayName("GererAvis tests") - class GererAvisTests { - - @Test - @DisplayName("Should create avis when valid data is provided") - void testGererAvisWithValidData() throws NotValidAvisException, CustomerNotFoundException { - when(customerRepository.findById(clientId)).thenReturn(Optional.of(testCustomer)); - - UUID avisId = UUID.randomUUID(); - Avis savedAvis = Avis.builder() - .id(avisId) - .clientId(clientId) - .livreId(livreId) - .note(5) - .commentaire("Excellent livre !") - .dateAchat(LocalDate.of(2024, 1, 15)) - .build(); - when(avisRepository.save(any(Avis.class))).thenReturn(savedAvis); - - AvisDTO result = avisUseCase.gererAvis(validAvisInfo); - - assertNotNull(result); - assertEquals(avisId, result.getAvisId()); - verify(avisRepository, times(1)).save(any(Avis.class)); - } - - @Test - @DisplayName("Should throw exception when customer does not exist") - void testGererAvisWithUnknownCustomer() { - when(customerRepository.findById(clientId)).thenReturn(Optional.empty()); - - assertThrows(CustomerNotFoundException.class, - () -> avisUseCase.gererAvis(validAvisInfo)); - - verify(avisRepository, never()).save(any(Avis.class)); - } - - @Test - @DisplayName("Should throw exception when note is invalid") - void testGererAvisWithInvalidNote() { - AvisInfo invalidAvis = new AvisInfo(clientId, livreId, 6, "Commentaire", LocalDate.now()); - - assertThrows(NotValidAvisException.class, - () -> avisUseCase.gererAvis(invalidAvis)); - - verify(avisRepository, never()).save(any(Avis.class)); - } - - @Test - @DisplayName("Should throw exception when commentaire is blank") - void testGererAvisWithBlankCommentaire() { - AvisInfo invalidAvis = new AvisInfo(clientId, livreId, 5, "", LocalDate.now()); - - assertThrows(NotValidAvisException.class, - () -> avisUseCase.gererAvis(invalidAvis)); - - verify(avisRepository, never()).save(any(Avis.class)); - } - - @Test - @DisplayName("Should throw exception when clientId is null") - void testGererAvisWithNullClientId() { - AvisInfo invalidAvis = new AvisInfo(null, livreId, 5, "Commentaire", LocalDate.now()); - - assertThrows(NotValidAvisException.class, - () -> avisUseCase.gererAvis(invalidAvis)); - - verify(avisRepository, never()).save(any(Avis.class)); - } - } - - @Nested - @DisplayName("FindAvis tests") - class FindAvisTests { - - @Test - @DisplayName("Should return avis when ID exists") - void testFindAvisById() { - UUID avisId = UUID.randomUUID(); - Avis avis = Avis.builder() - .id(avisId) - .clientId(clientId) - .livreId(livreId) - .note(5) - .commentaire("Excellent !") - .dateAchat(LocalDate.now()) - .build(); - - when(avisRepository.findById(avisId)).thenReturn(Optional.of(avis)); - - Optional result = avisUseCase.findAvisById(avisId); - - assertTrue(result.isPresent()); - assertEquals(avisId, result.get().getAvisId()); - } - - @Test - @DisplayName("Should return empty Optional when ID does not exist") - void testFindAvisByIdNotFound() { - UUID nonExistentId = UUID.randomUUID(); - when(avisRepository.findById(nonExistentId)).thenReturn(Optional.empty()); - - Optional result = avisUseCase.findAvisById(nonExistentId); - - assertTrue(result.isEmpty()); - } - } -} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidator.java new file mode 100644 index 0000000..0f4d0d8 --- /dev/null +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidator.java @@ -0,0 +1,54 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.avis.validator; + +import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; + +public final class AvisValidator { + + public static final String CLIENT_ID_CANNOT_BE_NULL = "Client id cannot be null"; + public static final String LIVRE_ID_CANNOT_BE_NULL = "Livre id cannot be null"; + public static final String NOTE_MUST_BE_BETWEEN_1_AND_5 = "Note must be between 1 and 5"; + public static final String COMMENTAIRE_CANNOT_BE_BLANK = "Commentaire cannot be blank"; + public static final String DATE_ACHAT_CANNOT_BE_NULL = "Date achat cannot be null"; + + private AvisValidator() { + } + + public static void validate(AvisInfo avisInfo) throws NotValidAvisException { + validateClientId(avisInfo); + validateLivreId(avisInfo); + validateNote(avisInfo); + validateCommentaire(avisInfo); + validateDateAchat(avisInfo); + } + + private static void validateClientId(AvisInfo avisInfo) throws NotValidAvisException { + if (avisInfo.clientId() == null) { + throw new NotValidAvisException(CLIENT_ID_CANNOT_BE_NULL); + } + } + + private static void validateLivreId(AvisInfo avisInfo) throws NotValidAvisException { + if (avisInfo.livreId() == null) { + throw new NotValidAvisException(LIVRE_ID_CANNOT_BE_NULL); + } + } + + private static void validateNote(AvisInfo avisInfo) throws NotValidAvisException { + if (avisInfo.note() < 1 || avisInfo.note() > 5) { + throw new NotValidAvisException(NOTE_MUST_BE_BETWEEN_1_AND_5); + } + } + + private static void validateCommentaire(AvisInfo avisInfo) throws NotValidAvisException { + if (avisInfo.commentaire() == null || avisInfo.commentaire().isBlank()) { + throw new NotValidAvisException(COMMENTAIRE_CANNOT_BE_BLANK); + } + } + + private static void validateDateAchat(AvisInfo avisInfo) throws NotValidAvisException { + if (avisInfo.dateAchat() == null) { + throw new NotValidAvisException(DATE_ACHAT_CANNOT_BE_NULL); + } + } +} \ No newline at end of file diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java deleted file mode 100644 index 3fee128..0000000 --- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/avis/validator/AvisValidatorTest.java +++ /dev/null @@ -1,131 +0,0 @@ -package fr.iut_fbleau.but3.dev62.mylibrary.avis.validator; - -import fr.iut_fbleau.but3.dev62.mylibrary.avis.AvisInfo; -import fr.iut_fbleau.but3.dev62.mylibrary.avis.exception.NotValidAvisException; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -import java.time.LocalDate; -import java.util.UUID; - -import static org.junit.jupiter.api.Assertions.*; - -class AvisValidatorTest { - - private final UUID clientId = UUID.randomUUID(); - private final UUID livreId = UUID.randomUUID(); - - private AvisInfo validAvis() { - return new AvisInfo(clientId, livreId, 5, "Excellent livre !", LocalDate.of(2024, 1, 15)); - } - - @Test - @DisplayName("Should validate avis with valid data") - void testValidateValidAvis() { - assertDoesNotThrow(() -> AvisValidator.validate(validAvis())); - } - - @Nested - @DisplayName("ClientId validation tests") - class ClientIdValidationTests { - - @Test - @DisplayName("Should throw exception when clientId is null") - void testValidateNullClientId() { - AvisInfo avis = new AvisInfo(null, livreId, 5, "Commentaire", LocalDate.now()); - - NotValidAvisException exception = assertThrows(NotValidAvisException.class, - () -> AvisValidator.validate(avis)); - - assertEquals(AvisValidator.CLIENT_ID_CANNOT_BE_NULL, exception.getMessage()); - } - } - - @Nested - @DisplayName("LivreId validation tests") - class LivreIdValidationTests { - - @Test - @DisplayName("Should throw exception when livreId is null") - void testValidateNullLivreId() { - AvisInfo avis = new AvisInfo(clientId, null, 5, "Commentaire", LocalDate.now()); - - NotValidAvisException exception = assertThrows(NotValidAvisException.class, - () -> AvisValidator.validate(avis)); - - assertEquals(AvisValidator.LIVRE_ID_CANNOT_BE_NULL, exception.getMessage()); - } - } - - @Nested - @DisplayName("Note validation tests") - class NoteValidationTests { - - @ParameterizedTest - @ValueSource(ints = {1, 2, 3, 4, 5}) - @DisplayName("Should validate when note is between 1 and 5") - void testValidateValidNote(int validNote) { - AvisInfo avis = new AvisInfo(clientId, livreId, validNote, "Commentaire", LocalDate.now()); - assertDoesNotThrow(() -> AvisValidator.validate(avis)); - } - - @ParameterizedTest - @ValueSource(ints = {0, -1, 6, 10}) - @DisplayName("Should throw exception when note is out of range") - void testValidateInvalidNote(int invalidNote) { - AvisInfo avis = new AvisInfo(clientId, livreId, invalidNote, "Commentaire", LocalDate.now()); - - NotValidAvisException exception = assertThrows(NotValidAvisException.class, - () -> AvisValidator.validate(avis)); - - assertEquals(AvisValidator.NOTE_MUST_BE_BETWEEN_1_AND_5, exception.getMessage()); - } - } - - @Nested - @DisplayName("Commentaire validation tests") - class CommentaireValidationTests { - - @Test - @DisplayName("Should throw exception when commentaire is blank") - void testValidateBlankCommentaire() { - AvisInfo avis = new AvisInfo(clientId, livreId, 5, "", LocalDate.now()); - - NotValidAvisException exception = assertThrows(NotValidAvisException.class, - () -> AvisValidator.validate(avis)); - - assertEquals(AvisValidator.COMMENTAIRE_CANNOT_BE_BLANK, exception.getMessage()); - } - - @ParameterizedTest - @ValueSource(strings = {" ", " ", "\t", "\n"}) - @DisplayName("Should throw exception when commentaire contains only whitespace") - void testValidateWhitespaceCommentaire(String whitespace) { - AvisInfo avis = new AvisInfo(clientId, livreId, 5, whitespace, LocalDate.now()); - - NotValidAvisException exception = assertThrows(NotValidAvisException.class, - () -> AvisValidator.validate(avis)); - - assertEquals(AvisValidator.COMMENTAIRE_CANNOT_BE_BLANK, exception.getMessage()); - } - } - - @Nested - @DisplayName("DateAchat validation tests") - class DateAchatValidationTests { - - @Test - @DisplayName("Should throw exception when dateAchat is null") - void testValidateNullDateAchat() { - AvisInfo avis = new AvisInfo(clientId, livreId, 5, "Commentaire", null); - - NotValidAvisException exception = assertThrows(NotValidAvisException.class, - () -> AvisValidator.validate(avis)); - - assertEquals(AvisValidator.DATE_ACHAT_CANNOT_BE_NULL, exception.getMessage()); - } - } -} \ No newline at end of file