From 2c777021b9b9a2ace232c52beb0612fc171a0871 Mon Sep 17 00:00:00 2001 From: jannaire Date: Sun, 12 Apr 2026 16:59:07 +0200 Subject: [PATCH] reglage order --- .../mylibrary/features/order/OrderSteps.java | 223 +++++++++++++++++ .../order/usecase/OrderUseCaseTest.java | 226 ++++++++++++++++++ 2 files changed, 449 insertions(+) create mode 100644 src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/order/OrderSteps.java create mode 100644 src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCaseTest.java diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/order/OrderSteps.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/order/OrderSteps.java new file mode 100644 index 0000000..ee4c44e --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/features/order/OrderSteps.java @@ -0,0 +1,223 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.features.order; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +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 fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; +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 fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison; +import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException; +import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository; +import fr.iut_fbleau.but3.dev62.mylibrary.order.usecase.OrderUseCase; +import io.cucumber.datatable.DataTable; +import io.cucumber.java.Before; +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import io.cucumber.java.en.When; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class OrderSteps { + + private final CustomerRepository customerRepository = new CustomerRepository(); + private final BookRepository bookRepository = new BookRepository(); + private final OrderRepository orderRepository = new OrderRepository(); + private final OrderUseCase orderUseCase = new OrderUseCase(orderRepository, customerRepository, bookRepository); + + private final Map customerPhoneUUID = new HashMap<>(); + private final Map bookIsbnUUID = new HashMap<>(); + + private OrderDTO orderResult; + private NotValidOrderException notValidOrderException; + private boolean customerNotFoundThrown = false; + + @Before + public void setUp() { + customerRepository.deleteAll(); + bookRepository.deleteAll(); + orderRepository.deleteAll(); + customerPhoneUUID.clear(); + bookIsbnUUID.clear(); + orderResult = null; + notValidOrderException = null; + customerNotFoundThrown = false; + } + + @Given("the system has the following customers for order:") + public void theSystemHasTheFollowingCustomersForOrder(DataTable dataTable) { + List> customers = dataTable.asMaps(String.class, String.class); + + for (Map customer : customers) { + String phone = customer.get("numeroTelephone"); + Customer newCustomer = Customer.builder() + .firstName(customer.get("prenom")) + .lastName(customer.get("nom")) + .phoneNumber(phone) + .loyaltyPoints(Integer.parseInt(customer.get("pointsFidelite"))) + .build(); + Customer saved = customerRepository.save(newCustomer); + customerPhoneUUID.put(phone, saved.getId()); + } + + assertEquals(customers.size(), customerRepository.findAll().size()); + } + + @And("the catalog has the following books for order:") + public void theCatalogHasTheFollowingBooksForOrder(DataTable dataTable) { + List> books = dataTable.asMaps(String.class, String.class); + + for (Map book : books) { + String isbn = book.get("isbn"); + Book newBook = Book.builder() + .isbn(isbn) + .title(book.get("titre")) + .author(book.get("auteur")) + .publisher(book.get("editeur")) + .publicationDate(LocalDate.parse(book.get("datePublication"))) + .price(new BigDecimal(book.get("prix"))) + .stock(Integer.parseInt(book.get("stockInitial"))) + .categories(List.of(book.get("categories").split(";"))) + .description(book.get("description")) + .language(book.get("langue")) + .build(); + Book saved = bookRepository.save(newBook); + bookIsbnUUID.put(isbn, saved.getId()); + } + + assertEquals(books.size(), bookRepository.findAll().size()); + } + + @When("I place an order for customer {string} with:") + public void iPlaceAnOrderForCustomerWith(String phoneNumber, DataTable dataTable) + throws NotValidOrderException, CustomerNotFoundException { + Map row = dataTable.asMaps(String.class, String.class).getFirst(); + + UUID customerId = customerPhoneUUID.get(phoneNumber); + UUID livreId = bookIsbnUUID.get(row.get("livreIsbn")); + + AdresseLivraison adresse = new AdresseLivraison( + row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays") + ); + + OrderInfo orderInfo = new OrderInfo( + customerId, + List.of(new LigneCommandeInfo(livreId, Integer.parseInt(row.get("quantite")))), + adresse, + ModePaiement.valueOf(row.get("modePaiement")) + ); + + orderResult = orderUseCase.passerCommande(orderInfo); + } + + @Then("a new order is created") + public void aNewOrderIsCreated() { + assertNotNull(orderResult); + assertNotNull(orderResult.getCommandeId()); + } + + @And("the order total is {double}") + public void theOrderTotalIs(double expectedTotal) { + assertEquals(0, new BigDecimal(String.valueOf(expectedTotal)).compareTo(orderResult.getMontantTotal())); + } + + @And("the customer {string} now has {int} loyalty points") + public void theCustomerNowHasLoyaltyPoints(String phoneNumber, int expectedPoints) { + UUID customerId = customerPhoneUUID.get(phoneNumber); + Customer customer = customerRepository.findById(customerId).orElseThrow(); + assertEquals(expectedPoints, customer.getLoyaltyPoints()); + } + + @When("I try to place an order for customer {string} with no items:") + public void iTryToPlaceAnOrderForCustomerWithNoItems(String phoneNumber, DataTable dataTable) { + Map row = dataTable.asMaps(String.class, String.class).getFirst(); + UUID customerId = customerPhoneUUID.get(phoneNumber); + + AdresseLivraison adresse = new AdresseLivraison( + row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays") + ); + + OrderInfo orderInfo = new OrderInfo( + customerId, List.of(), adresse, ModePaiement.valueOf(row.get("modePaiement")) + ); + + notValidOrderException = assertThrows(NotValidOrderException.class, + () -> orderUseCase.passerCommande(orderInfo)); + } + + @When("I try to place an order for customer {string} with invalid quantity:") + public void iTryToPlaceAnOrderForCustomerWithInvalidQuantity(String phoneNumber, DataTable dataTable) { + Map row = dataTable.asMaps(String.class, String.class).getFirst(); + UUID customerId = customerPhoneUUID.get(phoneNumber); + UUID livreId = bookIsbnUUID.get(row.get("livreIsbn")); + + AdresseLivraison adresse = new AdresseLivraison( + row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays") + ); + + OrderInfo orderInfo = new OrderInfo( + customerId, + List.of(new LigneCommandeInfo(livreId, Integer.parseInt(row.get("quantite")))), + adresse, + ModePaiement.valueOf(row.get("modePaiement")) + ); + + notValidOrderException = assertThrows(NotValidOrderException.class, + () -> orderUseCase.passerCommande(orderInfo)); + } + + @When("I try to place an order for an unknown customer with:") + public void iTryToPlaceAnOrderForAnUnknownCustomerWith(DataTable dataTable) { + Map row = dataTable.asMaps(String.class, String.class).getFirst(); + UUID unknownId = UUID.randomUUID(); + UUID livreId = bookIsbnUUID.get(row.get("livreIsbn")); + + AdresseLivraison adresse = new AdresseLivraison( + row.get("rue"), row.get("ville"), row.get("codePostal"), row.get("pays") + ); + + OrderInfo orderInfo = new OrderInfo( + unknownId, + List.of(new LigneCommandeInfo(livreId, Integer.parseInt(row.get("quantite")))), + adresse, + ModePaiement.valueOf(row.get("modePaiement")) + ); + + try { + orderUseCase.passerCommande(orderInfo); + } catch (CustomerNotFoundException e) { + customerNotFoundThrown = true; + } catch (NotValidOrderException e) { + notValidOrderException = e; + } + } + + @Then("the order placement fails") + public void theOrderPlacementFails() { + assertNotNull(notValidOrderException); + } + + @Then("the order placement fails with customer not found") + public void theOrderPlacementFailsWithCustomerNotFound() { + assertTrue(customerNotFoundThrown); + } + + @And("I receive a validation order error containing {string}") + public void iReceiveAValidationOrderErrorContaining(String errorMessage) { + assertEquals(errorMessage, notValidOrderException.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCaseTest.java b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCaseTest.java new file mode 100644 index 0000000..6cb30c6 --- /dev/null +++ b/src/test/java/fr/iut_fbleau/but3/dev62/mylibrary/order/usecase/OrderUseCaseTest.java @@ -0,0 +1,226 @@ +package fr.iut_fbleau.but3.dev62.mylibrary.order.usecase; + +import fr.iut_fbleau.but3.dev62.mylibrary.book.entity.Book; +import fr.iut_fbleau.but3.dev62.mylibrary.book.repository.BookRepository; +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 fr.iut_fbleau.but3.dev62.mylibrary.order.AdresseLivraison; +import fr.iut_fbleau.but3.dev62.mylibrary.order.LigneCommandeInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.order.ModePaiement; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderDTO; +import fr.iut_fbleau.but3.dev62.mylibrary.order.OrderInfo; +import fr.iut_fbleau.but3.dev62.mylibrary.order.entity.Order; +import fr.iut_fbleau.but3.dev62.mylibrary.order.exception.NotValidOrderException; +import fr.iut_fbleau.but3.dev62.mylibrary.order.repository.OrderRepository; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import java.util.UUID; +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 static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class OrderUseCaseTest { + + @Mock + private OrderRepository orderRepository; + + @Mock + private CustomerRepository customerRepository; + + @Mock + private BookRepository bookRepository; + + @InjectMocks + private OrderUseCase orderUseCase; + + private UUID customerId; + private UUID bookId; + private Customer testCustomer; + private Book testBook; + private AdresseLivraison adresse; + private OrderInfo validOrderInfo; + + @BeforeEach + void setUp() { + customerId = UUID.randomUUID(); + bookId = UUID.randomUUID(); + + testCustomer = Customer.builder() + .id(customerId) + .firstName("Marie") + .lastName("Dupont") + .phoneNumber("0612345678") + .loyaltyPoints(100) + .build(); + + testBook = Book.builder() + .id(bookId) + .isbn("9782016289308") + .title("Le Petit Prince") + .author("Antoine de Saint-Exupery") + .publisher("Gallimard") + .publicationDate(LocalDate.of(1943, 4, 6)) + .price(new BigDecimal("12.90")) + .stock(10) + .categories(List.of("Roman")) + .description("Un classique") + .language("FR") + .build(); + + adresse = new AdresseLivraison("1 rue de Paris", "Paris", "75001", "France"); + + validOrderInfo = new OrderInfo( + customerId, + List.of(new LigneCommandeInfo(bookId, 2)), + adresse, + ModePaiement.CB + ); + } + + @Nested + @DisplayName("PasserCommande tests") + class PasserCommandeTests { + + @Test + @DisplayName("Should place order when valid data is provided") + void testPasserCommandeWithValidData() throws NotValidOrderException, CustomerNotFoundException { + when(customerRepository.findById(customerId)).thenReturn(Optional.of(testCustomer)); + when(bookRepository.findById(bookId)).thenReturn(Optional.of(testBook)); + when(customerRepository.save(any(Customer.class))).thenReturn(testCustomer); + + UUID orderId = UUID.randomUUID(); + Order savedOrder = Order.builder() + .id(orderId) + .clientId(customerId) + .montantTotal(new BigDecimal("25.80")) + .pointsFideliteGagnes(25) + .build(); + when(orderRepository.save(any(Order.class))).thenReturn(savedOrder); + + OrderDTO result = orderUseCase.passerCommande(validOrderInfo); + + assertNotNull(result); + assertEquals(orderId, result.getCommandeId()); + verify(orderRepository, times(1)).save(any(Order.class)); + verify(customerRepository, times(1)).save(any(Customer.class)); + } + + @Test + @DisplayName("Should throw exception when customer does not exist") + void testPasserCommandeWithUnknownCustomer() { + when(customerRepository.findById(customerId)).thenReturn(Optional.empty()); + + assertThrows(CustomerNotFoundException.class, + () -> orderUseCase.passerCommande(validOrderInfo)); + + verify(orderRepository, never()).save(any(Order.class)); + } + + @Test + @DisplayName("Should throw exception when order has no items") + void testPasserCommandeWithNoItems() { + OrderInfo emptyOrder = new OrderInfo(customerId, List.of(), adresse, ModePaiement.CB); + + assertThrows(NotValidOrderException.class, + () -> orderUseCase.passerCommande(emptyOrder)); + + verify(orderRepository, never()).save(any(Order.class)); + } + + @Test + @DisplayName("Should throw exception when quantity is zero or negative") + void testPasserCommandeWithInvalidQuantity() { + OrderInfo invalidQty = new OrderInfo( + customerId, + List.of(new LigneCommandeInfo(bookId, 0)), + adresse, + ModePaiement.CB + ); + + assertThrows(NotValidOrderException.class, + () -> orderUseCase.passerCommande(invalidQty)); + + verify(orderRepository, never()).save(any(Order.class)); + } + + @Test + @DisplayName("Should throw exception when clientId is null") + void testPasserCommandeWithNullClientId() { + OrderInfo nullClient = new OrderInfo( + null, + List.of(new LigneCommandeInfo(bookId, 1)), + adresse, + ModePaiement.CB + ); + + assertThrows(NotValidOrderException.class, + () -> orderUseCase.passerCommande(nullClient)); + + verify(orderRepository, never()).save(any(Order.class)); + } + + @Test + @DisplayName("Should throw exception when payment method is null") + void testPasserCommandeWithNullModePaiement() { + OrderInfo nullPayment = new OrderInfo( + customerId, + List.of(new LigneCommandeInfo(bookId, 1)), + adresse, + null + ); + + assertThrows(NotValidOrderException.class, + () -> orderUseCase.passerCommande(nullPayment)); + + verify(orderRepository, never()).save(any(Order.class)); + } + } + + @Nested + @DisplayName("FindOrder tests") + class FindOrderTests { + + @Test + @DisplayName("Should return order when ID exists") + void testFindOrderById() { + UUID orderId = UUID.randomUUID(); + Order order = Order.builder() + .id(orderId) + .clientId(customerId) + .montantTotal(new BigDecimal("25.80")) + .pointsFideliteGagnes(25) + .build(); + + when(orderRepository.findById(orderId)).thenReturn(Optional.of(order)); + + Optional result = orderUseCase.findOrderById(orderId); + + assertTrue(result.isPresent()); + assertEquals(orderId, result.get().getCommandeId()); + } + + @Test + @DisplayName("Should return empty Optional when ID does not exist") + void testFindOrderByIdNotFound() { + UUID nonExistentId = UUID.randomUUID(); + when(orderRepository.findById(nonExistentId)).thenReturn(Optional.empty()); + + Optional result = orderUseCase.findOrderById(nonExistentId); + + assertTrue(result.isEmpty()); + } + } +} \ No newline at end of file