Main #5

Closed
Wilfried BRIGITTE wants to merge 3 commits from bridja/mylibrary-template:main into main
17 changed files with 1030 additions and 0 deletions
@@ -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;
}
@@ -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
) {
}
@@ -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();
}
}
@@ -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();
}
}
@@ -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));
}
}
@@ -0,0 +1,8 @@
package fr.iut_fbleau.but3.dev62.mylibrary.avis.exception;
public class NotValidAvisException extends Exception {
public NotValidAvisException(String message) {
super(message);
}
}
@@ -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<Avis> avisList = new ArrayList<>();
public List<Avis> findAll() {
return avisList;
}
public void deleteAll() {
avisList.clear();
}
public Avis save(Avis newAvis) {
Optional<Avis> existing = this.findById(newAvis.getId());
existing.ifPresentOrElse(avisList::remove, newAvis::setRandomUUID);
this.avisList.add(newAvis);
return newAvis;
}
public Optional<Avis> 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<Avis> findByLivreId(UUID livreId) {
return this.avisList.stream()
.filter(avis -> avis.getLivreId().equals(livreId))
.toList();
}
public List<Avis> findByClientId(UUID clientId) {
return this.avisList.stream()
.filter(avis -> avis.getClientId().equals(clientId))
.toList();
}
public void delete(Avis avis) {
avisList.remove(avis);
}
}
@@ -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<AvisDTO> findAvisById(UUID uuid) {
return avisRepository.findById(uuid).map(AvisConverter::toDTO);
}
}
@@ -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);
}
}
}
@@ -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());
}
}
}
@@ -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());
}
}
@@ -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()));
}
}
}
@@ -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());
}
}
}
@@ -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<Avis> 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<Avis> found = repository.findById(UUID.randomUUID());
assertTrue(found.isEmpty());
}
@Test
@DisplayName("FindByLivreId should return all avis for a book")
void testFindByLivreId() {
List<Avis> found = repository.findByLivreId(livreId1);
assertEquals(2, found.size());
}
@Test
@DisplayName("FindByClientId should return all avis for a client")
void testFindByClientId() {
List<Avis> 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());
}
}
}
@@ -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<AvisDTO> 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<AvisDTO> result = avisUseCase.findAvisById(nonExistentId);
assertTrue(result.isEmpty());
}
}
}
@@ -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());
}
}
}
+54
View File
@@ -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