From 4d47cdd9a012314a333c6f1d9983d7db7dbc7343 Mon Sep 17 00:00:00 2001 From: felix-vi Date: Tue, 28 Apr 2026 18:18:23 +0200 Subject: [PATCH] =?UTF-8?q?:white=5Fcheck=5Fmark:=20test=20des=20usecase?= =?UTF-8?q?=20cr=C3=A9er?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../book/validator/BookValidator.java | 7 +- .../dev62/mylibrary/book/entity/BookTest.java | 4 +- .../book/repository/BookRepositoryTest.java | 2 +- .../book/usecase/BookUseCaseTest.java | 345 ++++++++++++++++++ 4 files changed, 351 insertions(+), 7 deletions(-) create mode 100644 src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java diff --git a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java index ca601b0..66626af 100644 --- a/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java +++ b/src/main/java/fr/iut_fbleau/but3/dev62/mylibrary/book/validator/BookValidator.java @@ -4,7 +4,6 @@ import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDetails; import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; import fr.iut_fbleau.but3.dev62.mylibrary.book.BookSalesInfo; import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException; -import fr.iut_fbleau.but3.dev62.mylibrary.customer.exception.NotValidCustomerException; import java.time.LocalDate; import java.util.ArrayList; @@ -24,7 +23,7 @@ public class BookValidator { private BookValidator() { } - public static void validate(BookInfo newBook) throws NotValidCustomerException { + public static void validate(BookInfo newBook) throws NotValidBookException { validateISBN(newBook); validateTitle(newBook); validateAuthor(newBook); @@ -32,12 +31,12 @@ public class BookValidator { validateDate(newBook); } - public static void validate(BookSalesInfo newBook) throws NotValidCustomerException { + public static void validate(BookSalesInfo newBook) throws NotValidBookException { validatePrice(newBook); validateStock(newBook); } - public static void validate(BookDetails newBook) throws NotValidCustomerException { + public static void validate(BookDetails newBook) throws NotValidBookException { validateCategories(newBook); validateLanguage(newBook); } diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/BookTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/BookTest.java index 1af2d9a..1cf6303 100644 --- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/BookTest.java +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/entity/BookTest.java @@ -15,8 +15,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; public class BookTest { @Test - @DisplayName("Builder should create a valid Customer instance") - void testCustomerBuilder() { + @DisplayName("Builder should create a valid Book instance") + void testBookBuilder() { String isbn = "1234567891012"; String title = "La vie de Maxime"; String author = "Marvin Aubert"; diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepositoryTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepositoryTest.java index 5d3d5e6..a6c5669 100644 --- a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepositoryTest.java +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/repository/BookRepositoryTest.java @@ -199,7 +199,7 @@ public class BookRepositoryTest { class DeleteOperations { @BeforeEach - void setUpCustomers() { + void setUpBooks() { repository.save(book1); repository.save(book2); } diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java new file mode 100644 index 0000000..5820538 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/book/usecase/BookUseCaseTest.java @@ -0,0 +1,345 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.book.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookDetails; +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.book.BookSalesInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +import fr.iut_fbleau.but3.dev62.mylibrary.book.exception.NotValidBookException; +import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; +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.ArrayList; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; +import static org.mockito.Mockito.never; + +@ExtendWith(MockitoExtension.class) +public class BookUseCaseTest { + + @Mock + private BookRepository bookRepository; + + @InjectMocks + private BookUseCase bookUseCase; + + private String bookIsbn; + private ArrayList categories; + private LocalDate date; + private Book testBook; + private BookInfo validBookInfo; + private BookDetails validBookDetails; + private BookSalesInfo validBookSalesInfo; + + @BeforeEach + void setUp() { + bookIsbn = "1234567891012"; + date = LocalDate.of(2026, 3, 24); + categories = new ArrayList<>(); + categories.add("Thriller"); + categories.add("Biographie"); + + testBook = Book.builder() + .isbn(bookIsbn) + .title("La vie de Maxime") + .author("Marvin AUbert") + .editor("Kioon") + .date(date) + .price(12.99) + .stock(50) + .categories(categories) + .description("C'était un brave partit trop tôt") + .language("Français") + .build(); + + validBookInfo = new BookInfo(bookIsbn,"La vie de Maxime", "Marvin AUbert", "Kioon", date); + validBookSalesInfo = BookSalesInfo.builder() + .price(12.99) + .stock(50) + .build(); + validBookDetails = BookDetails.builder() + .categories(categories) + .description("C'était un brave partit trop tôt") + .language("Français") + .build(); + } + + @Nested + @DisplayName("Register Book tests") + class RegisterBookTests { + + @Test + @DisplayName("Should register book when valid data is provided") + void testRegisterBookWithValidData() throws NotValidBookException { + when(bookRepository.save(any(Book.class))).thenReturn(testBook); + + String registeredIsbn = bookUseCase.registerBook(validBookInfo); + + assertNotNull(registeredIsbn); + assertEquals(bookIsbn, registeredIsbn); + verify(bookRepository, times(1)).save(any(Book.class)); + } + + @Test + @DisplayName("Should throw exception when book data is not valid") + void testRegisterBookWithInvalidData() { + BookInfo invalidBookInfo = new BookInfo(bookIsbn,"", "", "", date); + + assertThrows(NotValidBookException.class, + () -> bookUseCase.registerBook(invalidBookInfo)); + + verify(bookRepository, never()).save(any(Book.class)); + } + } + + @Nested + @DisplayName("Find book tests") + class FindBookTests { + + @Test + @DisplayName("Should return book when isbn exists") + void testFindBookByIsbn() { + when(bookRepository.findByIsbn("1234567891012")).thenReturn(Optional.of(testBook)); + + Optional foundBook = bookUseCase.findBookByIsbn("1234567891012"); + + assertTrue(foundBook.isPresent()); + assertEquals(testBook.getIsbn(), foundBook.get().getIsbn()); + assertEquals(testBook.getTitle(), foundBook.get().getTitle()); + verify(bookRepository, times(1)).findByIsbn("1234567891012"); + } + + @Test + @DisplayName("Should return empty Optional when isbn doesn't exist") + void testFindBookByIsbn() { + when(bookRepository.findByIsbn("1656546262516")).thenReturn(Optional.empty()); + + Optional foundBook = bookUseCase.findBookByIsbn("1656546262516"); + + assertTrue(foundBook.isEmpty()); + verify(bookRepository, times(1)).findByIsbn("1656546262516"); + } + } + + @Nested + @DisplayName("Update book tests") + class UpdateBookTests { + + @Test + @DisplayName("Should update book when valid data is provided") + void testUpdateBookWithValidData() throws BookNotFoundException, NotValidBookException { + when(bookRepository.findByIsbn(bookIsbn)).thenReturn(Optional.of(testBook)); + + Book updatedBook = Book.builder() + .isbn(bookIsbn) + .title("La vie de Maxime") + .author("Updated") + .editor("Kioon") + .date(date) + .price(12.99) + .stock(50) + .categories(categories) + .description("C'était un brave partit trop tôt") + .language("Français") + .build(); + + when(bookRepository.save(any(Book.class))).thenReturn(updatedBook); + + BookInfo updateInfo = new BookInfo(bookIsbn, "La vie de Maxime", "Updated", "Kioon", date); + BookSalesInfo updateSalesInfo = BookSalesInfo.builder() + .price(12.99) + .stock(50) + .build(); + BookDetails updateDetails = BookDetails.builder() + .categories(categories) + .description("C'était un brave partit trop tôt") + .language("Français") + .build(); + BookDTO result = BookUseCase.updateBook(updateInfo, updateSalesInfo, updateDetails); + + assertNotNull(result); + assertEquals(bookIsbn, result.getIsbn()); + assertEquals("La vie de Maxime", result.getTitle()); + assertEquals("Updated", result.getAuthor()); + assertEquals("Kioon", result.getEditor()); + assertEquals(date, result.getDate()); + assertEquals(12.99, result.getPrice()); + assertEquals(50, result.getStock()); + assertEquals(categories, result.getCategories()); + assertEquals("C'était un brave partit trop tôt", result.getDescription()); + assertEquals("Français", result.getLanguage()); + verify(bookRepository, times(1)).findByIsbn(bookIsbn); + verify(bookRepository, times(1)).save(any(Book.class)); + } + + @Test + @DisplayName("Should throw exception when book isbn doesn't exist") + void testUpdateBookNotFound() { + String nonExistentIsbn = "1656546262516"; + when(bookRepository.findByIsbn(nonExistentIsbn)).thenReturn(Optional.empty()); + + BookInfo updateInfo = new BookInfo(nonExistentIsbn, "La vie de Maxime", "Updated", "Kioon", date); + BookSalesInfo updateSalesInfo = BookSalesInfo.builder() + .price(12.99) + .stock(50) + .build(); + BookDetails updateDetails = BookDetails.builder() + .categories(categories) + .description("C'était un brave partit trop tôt") + .language("Français") + .build(); + + assertThrows(BookNotFoundException.class, + () -> bookUseCase.updateBook(updateInfo, updateSalesInfo, updateDetails)); + + verify(bookRepository, times(1)).findByIsbn(nonExistentIsbn); + verify(bookRepository, never()).save(any(Book.class)); + } + + @Test + @DisplayName("Should throw exception when update data is not valid") + void testUpdateBookWithInvalidData() { + BookInfo invalidUpdateInfo = new BookInfo(bookIsbn,"", "", "", date); + BookSalesInfo invalidUpdateSalesInfo = BookSalesInfo.builder() + .price(0) + .stock(-3) + .build(); + BookDetails invalidUpdateDetails = BookDetails.builder() + .categories(categories) + .description("") + .language("") + .build(); + + assertThrows(NotValidBookException.class, + () -> bookUseCase.updateBook(invalidUpdateInfo, invalidUpdateSalesInfo, invalidUpdateDetails)); + + verify(bookRepository, never()).findByIsbn(any(String.class)); + verify(bookRepository, never()).save(any(Book.class)); + } + } + + @Nested + @DisplayName("Delete book tests") + class DeleteBookTests { + + @Test + @DisplayName("Should delete book when isbn exists") + void testDeleteBook() throws BookNotFoundException { + when(bookRepository.findByIsbn(bookIsbn)).thenReturn(Optional.of(testBook)); + doNothing().when(bookRepository).delete(testBook); + + bookUseCase.deleteBook(bookIsbn); + + verify(bookRepository, times(1)).findByIsbn(bookIsbn); + verify(bookRepository, times(1)).delete(testBook); + } + + @Test + @DisplayName("Should throw exception when book isbn doesn't exist") + void testDeleteBookNotFound() { + String nonExistentIsbn = "1656546262516"; + when(bookRepository.findByIsbn(nonExistentIsbn)).thenReturn(Optional.empty()); + + assertThrows(BookNotFoundException.class, + () -> bookUseCase.deleteBook(nonExistentIsbn)); + + verify(bookRepository, times(1)).findByIsbn(nonExistentIsbn); + verify(bookRepository, never()).delete(any(Book.class)); + } + } + + @Nested + @DisplayName("Stock copies tests") + class StockCopiesTests { + + @Test + @DisplayName("Should add stock copies to book") + void testAddStockCopies() throws BookNotFoundException { + when(bookRepository.findByIsbn(bookIsbn)).thenReturn(Optional.of(testBook)); + when(bookRepository.save(testBook)).thenReturn(testBook); + + int initialCopies = testBook.getStock(); + int copiesToAdd = 50; + int expectedCopies = initialCopies + copiesToAdd; + + int newCopies = bookUseCase.addStockCopies(bookIsbn, copiesToAdd); + + assertEquals(expectedCopies, newCopies); + assertEquals(expectedCopies, testBook.getStock()); + verify(bookRepository, times(1)).findByIsbn(bookIsbn); + verify(bookRepository, times(1)).save(testBook); + } + + @Test + @DisplayName("Should throw exception when adding copies to non-existent book") + void testAddStockCopiesToNonExistentBook() { + String nonExistentIsbn = "1656546262516"; + when(bookRepository.findByIsbn(nonExistentIsbn)).thenReturn(Optional.empty()); + + assertThrows(BookNotFoundException.class, + () -> bookUseCase.addStockCopies(nonExistentIsbn, 50)); + + verify(bookRepository, times(1)).findByIsbn(nonExistentIsbn); + verify(bookRepository, never()).save(any(Book.class)); + } + + @Test + @DisplayName("Should subtract stock copies from book") + void testSubtractStockCopies() throws BookNotFoundException, IllegalBookCpoiesException { + when(bookRepository.findByIsbn(bookIsbn)).thenReturn(Optional.of(testBook)); + when(bookRepository.save(testBook)).thenReturn(testBook); + + int initialCopies = testBook.getStock(); + int copiesToRemove = 30; + int expectedCopies = initialCopies - copiesToRemove; + + int newCopies = bookUseCase.subtractStockCopies(bookIsbn, copiesToRemove); + + assertEquals(expectedCopies, newCopies); + assertEquals(expectedCopies, testBook.getStock()); + verify(bookRepository, times(1)).findByIsbn(bookIsbn); + verify(bookRepository, times(1)).save(testBook); + } + + @Test + @DisplayName("Should throw exception when trying to remove more copies than available") + void testSubtractTooManyStockCopies() { + when(bookRepository.findByIsbn(bookIsbn)).thenReturn(Optional.of(testBook)); + + int copiesToRemove = 200; + + assertThrows(IllegalBookCpoiesException.class, + () -> bookUseCase.subtractStockCopies(bookIsbn, copiesToRemove)); + + verify(bookRepository, times(1)).findByIsbn(bookIsbn); + verify(bookRepository, never()).save(any(Book.class)); + } + + @Test + @DisplayName("Should throw exception when subtracting copies from non-existent book") + void testSubtractStockCopiesFromNonExistentBook() { + String nonExistentIsbn = "1656546262516"; + when(bookRepository.findByIsbn(nonExistentIsbn)).thenReturn(Optional.empty()); + + assertThrows(BookNotFoundException.class, + () -> bookUseCase.subtractStockCopies(nonExistentIsbn, 50)); + + verify(bookRepository, times(1)).findByIsbn(nonExistentIsbn); + verify(bookRepository, never()).save(any(Book.class)); + } + } +}