From 377b337aa9f31d661a189f0487e778dd1128f777 Mon Sep 17 00:00:00 2001 From: mIst Date: Fri, 29 Sep 2023 15:00:11 +0300 Subject: [PATCH] added tests for ShoppingCart and CartItem entities --- .../dto/cartitem/CartItemCreateDto.java | 2 + .../dto/cartitem/CartItemResponseDto.java | 2 + .../dto/cartitem/CartItemUpdateDto.java | 2 + .../dto/shoppingcart/ShoppingCartDto.java | 2 + .../java/com/bookstore/model/CartItem.java | 2 + .../com/bookstore/model/ShoppingCart.java | 2 + src/main/java/com/bookstore/model/User.java | 2 + .../service/impl/ShoppingCartServiceImpl.java | 15 +- .../ShoppingCartControllerTest.java | 285 +++++++++++++ .../impl/ShoppingCartServiceImplTest.java | 376 ++++++++++++++++++ .../cart_items/add-test-cart-item.sql | 2 + .../cart_items/delete-test-cart-item.sql | 1 + .../cart_items/delete-updated-cart-items.sql | 1 + .../add-three-default-shopping-carts.sql | 3 + .../delete-from-shopping_carts.sql | 1 + .../users/add-three-default-users.sql | 6 + .../database/users/delete-from-users.sql | 1 + 17 files changed, 696 insertions(+), 9 deletions(-) create mode 100644 src/test/java/com/bookstore/controller/ShoppingCartControllerTest.java create mode 100644 src/test/java/com/bookstore/service/impl/ShoppingCartServiceImplTest.java create mode 100644 src/test/resources/database/cart_items/add-test-cart-item.sql create mode 100644 src/test/resources/database/cart_items/delete-test-cart-item.sql create mode 100644 src/test/resources/database/cart_items/delete-updated-cart-items.sql create mode 100644 src/test/resources/database/shopping_carts/add-three-default-shopping-carts.sql create mode 100644 src/test/resources/database/shopping_carts/delete-from-shopping_carts.sql create mode 100644 src/test/resources/database/users/add-three-default-users.sql create mode 100644 src/test/resources/database/users/delete-from-users.sql diff --git a/src/main/java/com/bookstore/dto/cartitem/CartItemCreateDto.java b/src/main/java/com/bookstore/dto/cartitem/CartItemCreateDto.java index 49be3c2..cb7f07c 100644 --- a/src/main/java/com/bookstore/dto/cartitem/CartItemCreateDto.java +++ b/src/main/java/com/bookstore/dto/cartitem/CartItemCreateDto.java @@ -3,7 +3,9 @@ import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import lombok.Data; +import lombok.experimental.Accessors; +@Accessors(chain = true) @Data public class CartItemCreateDto { @NotNull diff --git a/src/main/java/com/bookstore/dto/cartitem/CartItemResponseDto.java b/src/main/java/com/bookstore/dto/cartitem/CartItemResponseDto.java index 0714f6b..fc7a155 100644 --- a/src/main/java/com/bookstore/dto/cartitem/CartItemResponseDto.java +++ b/src/main/java/com/bookstore/dto/cartitem/CartItemResponseDto.java @@ -1,7 +1,9 @@ package com.bookstore.dto.cartitem; import lombok.Data; +import lombok.experimental.Accessors; +@Accessors(chain = true) @Data public class CartItemResponseDto { private Long id; diff --git a/src/main/java/com/bookstore/dto/cartitem/CartItemUpdateDto.java b/src/main/java/com/bookstore/dto/cartitem/CartItemUpdateDto.java index 71d0130..5471463 100644 --- a/src/main/java/com/bookstore/dto/cartitem/CartItemUpdateDto.java +++ b/src/main/java/com/bookstore/dto/cartitem/CartItemUpdateDto.java @@ -3,7 +3,9 @@ import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import lombok.Data; +import lombok.experimental.Accessors; +@Accessors(chain = true) @Data public class CartItemUpdateDto { @NotNull diff --git a/src/main/java/com/bookstore/dto/shoppingcart/ShoppingCartDto.java b/src/main/java/com/bookstore/dto/shoppingcart/ShoppingCartDto.java index 1861f9f..a191189 100644 --- a/src/main/java/com/bookstore/dto/shoppingcart/ShoppingCartDto.java +++ b/src/main/java/com/bookstore/dto/shoppingcart/ShoppingCartDto.java @@ -3,7 +3,9 @@ import com.bookstore.dto.cartitem.CartItemResponseDto; import java.util.Set; import lombok.Data; +import lombok.experimental.Accessors; +@Accessors(chain = true) @Data public class ShoppingCartDto { private Long userId; diff --git a/src/main/java/com/bookstore/model/CartItem.java b/src/main/java/com/bookstore/model/CartItem.java index e7fc6d1..04de97b 100644 --- a/src/main/java/com/bookstore/model/CartItem.java +++ b/src/main/java/com/bookstore/model/CartItem.java @@ -11,7 +11,9 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; +import lombok.experimental.Accessors; +@Accessors(chain = true) @Getter @Setter @EqualsAndHashCode diff --git a/src/main/java/com/bookstore/model/ShoppingCart.java b/src/main/java/com/bookstore/model/ShoppingCart.java index 2b0a12e..25ed40e 100644 --- a/src/main/java/com/bookstore/model/ShoppingCart.java +++ b/src/main/java/com/bookstore/model/ShoppingCart.java @@ -14,8 +14,10 @@ import lombok.Getter; import lombok.Setter; import lombok.ToString; +import lombok.experimental.Accessors; import org.hibernate.annotations.SQLDelete; +@Accessors(chain = true) @Getter @Setter @EqualsAndHashCode diff --git a/src/main/java/com/bookstore/model/User.java b/src/main/java/com/bookstore/model/User.java index 70e76f7..211bd3e 100644 --- a/src/main/java/com/bookstore/model/User.java +++ b/src/main/java/com/bookstore/model/User.java @@ -14,12 +14,14 @@ import java.util.stream.Collectors; import lombok.Getter; import lombok.Setter; +import lombok.experimental.Accessors; import org.hibernate.annotations.SQLDelete; import org.hibernate.annotations.Where; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; +@Accessors(chain = true) @Getter @Setter @Entity diff --git a/src/main/java/com/bookstore/service/impl/ShoppingCartServiceImpl.java b/src/main/java/com/bookstore/service/impl/ShoppingCartServiceImpl.java index fd9310f..76bca6d 100644 --- a/src/main/java/com/bookstore/service/impl/ShoppingCartServiceImpl.java +++ b/src/main/java/com/bookstore/service/impl/ShoppingCartServiceImpl.java @@ -9,11 +9,9 @@ import com.bookstore.model.Book; import com.bookstore.model.CartItem; import com.bookstore.model.ShoppingCart; -import com.bookstore.model.User; import com.bookstore.repository.book.BookRepository; import com.bookstore.repository.cartitem.CartItemRepository; import com.bookstore.repository.shoppingcart.ShoppingCartRepository; -import com.bookstore.repository.user.UserRepository; import com.bookstore.service.ShoppingCartService; import jakarta.transaction.Transactional; import java.util.HashSet; @@ -27,7 +25,6 @@ public class ShoppingCartServiceImpl implements ShoppingCartService { private final ShoppingCartRepository shoppingCartRepository; private final ShoppingCartMapper shoppingCartMapper; - private final UserRepository userRepository; private final CartItemMapper cartItemMapper; private final CartItemRepository cartItemRepository; private final BookRepository bookRepository; @@ -55,7 +52,7 @@ public ShoppingCartDto saveBookToTheCart(Long userId, CartItemCreateDto cartItem CartItem cartItem = cartItemMapper.toEntity(cartItemCreateDto, book, shoppingCart); cartItemRepository.save(cartItem); shoppingCart.addCartItemToSet(cartItem); - return shoppingCartMapper.toDto(getShoppingCartByUserId(userId)); + return shoppingCartMapper.toDto(shoppingCart); } @Override @@ -74,18 +71,18 @@ public ShoppingCartDto update(Long userId, @Override public void deleteCartItemFromTheCart(Long id) { + if (cartItemRepository.findById(id).isEmpty()) { + throw new EntityNotFoundException("Can't delete a cart item from DB with id: " + id); + } cartItemRepository.deleteById(id); } @Override public ShoppingCart getShoppingCartByUserId(Long id) { - User user = userRepository.findById(id) - .orElseThrow(() -> - new EntityNotFoundException("Can't find user in DB by id: " + id)); - return shoppingCartRepository.findByUserId(user.getId()) + return shoppingCartRepository.findByUserId(id) .orElseThrow(() -> new EntityNotFoundException( - "Can't find a shopping cart by id: " + user.getId() + "Can't find a shopping cart by user id: " + id )); } diff --git a/src/test/java/com/bookstore/controller/ShoppingCartControllerTest.java b/src/test/java/com/bookstore/controller/ShoppingCartControllerTest.java new file mode 100644 index 0000000..d5ddf1e --- /dev/null +++ b/src/test/java/com/bookstore/controller/ShoppingCartControllerTest.java @@ -0,0 +1,285 @@ +package com.bookstore.controller; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.bookstore.dto.cartitem.CartItemCreateDto; +import com.bookstore.dto.cartitem.CartItemResponseDto; +import com.bookstore.dto.cartitem.CartItemUpdateDto; +import com.bookstore.dto.shoppingcart.ShoppingCartDto; +import com.bookstore.model.Role; +import com.bookstore.model.User; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.sql.DataSource; +import lombok.SneakyThrows; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.MediaType; +import org.springframework.jdbc.datasource.init.ScriptUtils; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +class ShoppingCartControllerTest { + protected static MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + + @BeforeAll + static void beforeAll( + @Autowired DataSource dataSource, + @Autowired WebApplicationContext applicationContext + ) throws SQLException { + mockMvc = MockMvcBuilders + .webAppContextSetup(applicationContext) + .apply(springSecurity()) + .build(); + teardown(dataSource); + try (Connection connection = dataSource.getConnection()) { + connection.setAutoCommit(true); + ScriptUtils.executeSqlScript( + connection, + new ClassPathResource("database/users/add-three-default-users.sql") + ); + ScriptUtils.executeSqlScript( + connection, + new ClassPathResource( + "database/shopping_carts/add-three-default-shopping-carts.sql") + ); + ScriptUtils.executeSqlScript( + connection, + new ClassPathResource("database/books-controller/add-three-default-books.sql") + ); + } + } + + @AfterAll + static void afterAll( + @Autowired DataSource dataSource + ) { + teardown(dataSource); + } + + @SneakyThrows + static void teardown(DataSource dataSource) { + try (Connection connection = dataSource.getConnection()) { + connection.setAutoCommit(true); + ScriptUtils.executeSqlScript( + connection, + new ClassPathResource("database/shopping_carts/delete-from-shopping_carts.sql") + ); + ScriptUtils.executeSqlScript( + connection, + new ClassPathResource("database/users/delete-from-users.sql") + ); + ScriptUtils.executeSqlScript( + connection, + new ClassPathResource("database/books-controller/delete-from-books.sql") + ); + } + } + + @WithMockUser(username = "admin", roles = {"ADMIN"}) + @Test + @DisplayName("Get all carts") + void getAll_GivenCartsInCatalog_ShouldReturnAllCarts() throws Exception { + //Given + List expected = new ArrayList<>(); + expected.add(new ShoppingCartDto().setUserId(1L).setCartItemsDto(new HashSet<>())); + expected.add(new ShoppingCartDto().setUserId(2L).setCartItemsDto(new HashSet<>())); + expected.add(new ShoppingCartDto().setUserId(3L).setCartItemsDto(new HashSet<>())); + + //When + MvcResult result = mockMvc.perform(get("/api/cart/all") + .contentType(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andReturn(); + + //Then + ShoppingCartDto[] actual = objectMapper.readValue( + result.getResponse().getContentAsByteArray(), + ShoppingCartDto[].class); + + assertEquals(expected.size(), actual.length); + assertEquals(expected, Arrays.stream(actual).toList()); + } + + @WithMockUser(username = "user", roles = {"USER", "ADMIN"}) + @Test + @DisplayName("Get user's shopping cart") + void getShoppingCartByUser_ValidUserId_ReturnsUsersCart() throws Exception { + //Given + User user = getUser(); + ShoppingCartDto expected = getShoppingCartDto(); + + //When + MvcResult result = mockMvc.perform(get("/api/cart") + .contentType(MediaType.APPLICATION_JSON) + .with(user(user)) + ) + .andExpect(status().isOk()) + .andReturn(); + + //Then + ShoppingCartDto actual = objectMapper.readValue(result.getResponse().getContentAsString(), + ShoppingCartDto.class); + + EqualsBuilder.reflectionEquals(expected, actual); + } + + @Sql(scripts = { + "classpath:database/cart_items/delete-test-cart-item.sql" + }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) + @Test + @DisplayName("Add book to the cart") + void addBookToTheCart_ValidCartItemCreateDto_ReturnsShoppingCartDto() throws Exception { + //Given + User user = getUser(); + + CartItemCreateDto cartItemCreateDto = new CartItemCreateDto() + .setBookId(1L) + .setQuantity(10); + + CartItemResponseDto expected = new CartItemResponseDto() + .setBookId(1L) + .setBookTitle("Test Title") + .setQuantity(cartItemCreateDto.getQuantity()); + + String jsonRequest = objectMapper.writeValueAsString(cartItemCreateDto); + + //When + MvcResult result = mockMvc.perform(post("/api/cart") + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .with(user(user)) + ) + .andExpect(status().isOk()) + .andReturn(); + + //Then + ShoppingCartDto actual = objectMapper.readValue(result.getResponse().getContentAsString(), + ShoppingCartDto.class); + + assertThat(actual.getCartItemsDto()).hasSize(1); + EqualsBuilder.reflectionEquals(expected, + actual.getCartItemsDto().stream().toList().get(0), "id"); + } + + @Sql(scripts = { + "classpath:database/cart_items/add-test-cart-item.sql" + }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = { + "classpath:database/cart_items/delete-updated-cart-items.sql" + }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) + @Test + void updateBookInTheCart_ValidCartItemUpdateDto_ReturnsShoppingCartDto() throws Exception { + //Given + User user = getUser(); + + Long cartItemId = -1L; + + CartItemUpdateDto cartItemUpdateDto = new CartItemUpdateDto() + .setQuantity(15); + + CartItemResponseDto expected = new CartItemResponseDto() + .setBookId(1L) + .setBookTitle("Test Title") + .setQuantity(cartItemUpdateDto.getQuantity()); + + String jsonRequest = objectMapper.writeValueAsString(cartItemUpdateDto); + + //When + MvcResult result = mockMvc.perform(put("/api/cart//cart-items/" + cartItemId) + .content(jsonRequest) + .contentType(MediaType.APPLICATION_JSON) + .with(user(user)) + ) + .andExpect(status().isOk()) + .andReturn(); + + //Then + ShoppingCartDto actual = objectMapper.readValue(result.getResponse().getContentAsString(), + ShoppingCartDto.class); + + assertThat(actual.getCartItemsDto()).hasSize(1); + EqualsBuilder.reflectionEquals(expected, + actual.getCartItemsDto().stream().toList().get(0), "id"); + } + + @WithMockUser(username = "user", roles = {"USER", "ADMIN"}) + @Sql(scripts = { + "classpath:database/cart_items/add-test-cart-item.sql" + }, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = { + "classpath:database/cart_items/delete-test-cart-item.sql" + }, executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) + @Test + @DisplayName("Remove book from the cart") + void removeBookFromTheCart_ValidCartItemId_DeletesABookFromTheCart() throws Exception { + //Given + Long cartItemId = -1L; + + //When + MvcResult result = mockMvc.perform(delete("/api/cart/cart-items/" + cartItemId) + .contentType(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isOk()) + .andReturn(); + } + + @WithMockUser(username = "user", roles = {"USER", "ADMIN"}) + @Test + @DisplayName("Remove book from the cart") + void removeBookFromTheCart_InvalidCartItemId_ShouldReturnBadRequest() throws Exception { + //Given + Long cartItemId = -100L; + + //When + MvcResult result = mockMvc.perform(delete("/api/cart/cart-items/" + cartItemId) + .contentType(MediaType.APPLICATION_JSON) + ) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + private ShoppingCartDto getShoppingCartDto() { + return new ShoppingCartDto() + .setUserId(1L) + .setCartItemsDto(new HashSet<>()); + } + + private User getUser() { + Set roles = new HashSet<>(); + Role role = new Role(); + role.setName(Role.RoleName.USER); + roles.add(role); + return new User() + .setId(1L) + .setRoles(roles); + } +} diff --git a/src/test/java/com/bookstore/service/impl/ShoppingCartServiceImplTest.java b/src/test/java/com/bookstore/service/impl/ShoppingCartServiceImplTest.java new file mode 100644 index 0000000..f7ab5e0 --- /dev/null +++ b/src/test/java/com/bookstore/service/impl/ShoppingCartServiceImplTest.java @@ -0,0 +1,376 @@ +package com.bookstore.service.impl; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import com.bookstore.dto.cartitem.CartItemCreateDto; +import com.bookstore.dto.cartitem.CartItemUpdateDto; +import com.bookstore.dto.shoppingcart.ShoppingCartDto; +import com.bookstore.exception.EntityNotFoundException; +import com.bookstore.mapper.CartItemMapper; +import com.bookstore.mapper.ShoppingCartMapper; +import com.bookstore.model.Book; +import com.bookstore.model.CartItem; +import com.bookstore.model.ShoppingCart; +import com.bookstore.model.User; +import com.bookstore.repository.book.BookRepository; +import com.bookstore.repository.cartitem.CartItemRepository; +import com.bookstore.repository.shoppingcart.ShoppingCartRepository; +import java.math.BigDecimal; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import org.junit.jupiter.api.DisplayName; +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 org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; + +@ExtendWith(MockitoExtension.class) +class ShoppingCartServiceImplTest { + @Mock + private ShoppingCartRepository shoppingCartRepository; + @Mock + private ShoppingCartMapper shoppingCartMapper; + @Mock + private CartItemMapper cartItemMapper; + @Mock + private CartItemRepository cartItemRepository; + @Mock + private BookRepository bookRepository; + @InjectMocks + private ShoppingCartServiceImpl shoppingCartService; + + @Test + @DisplayName("Verify finAll() method works") + void findAll_ValidPageable_ReturnsAllCarts() { + //Given + ShoppingCart shoppingCart = getShoppingCart(); + + ShoppingCartDto shoppingCartDto = getShoppingCartDtoFromCart(shoppingCart); + + Pageable pageable = PageRequest.of(0, 10); + List shoppingCarts = List.of(shoppingCart); + + Page shoppingCartPage = + new PageImpl<>(shoppingCarts, pageable, shoppingCarts.size()); + + when(shoppingCartRepository.findAll(pageable)).thenReturn(shoppingCartPage); + when(shoppingCartMapper.toDto(shoppingCart)).thenReturn(shoppingCartDto); + + //When + List shoppingCartDtos = shoppingCartService.findAll(pageable); + + //Then + assertThat(shoppingCartDtos).hasSize(1); + assertThat(shoppingCartDtos.get(0)).isEqualTo(shoppingCartDto); + + verify(shoppingCartRepository, times(1)).findAll(pageable); + verify(shoppingCartMapper, times(1)).toDto(shoppingCart); + verifyNoMoreInteractions(shoppingCartRepository, shoppingCartMapper); + } + + @Test + @DisplayName("Verify getByUserId() method works") + void getByUserId_ValidUserId_ReturnsUsersCart() { + //Given + Long userId = 1L; + + ShoppingCart shoppingCart = getShoppingCart(); + + ShoppingCartDto expected = getShoppingCartDtoFromCart(shoppingCart); + + when(shoppingCartRepository.findByUserId(anyLong())).thenReturn(Optional.of(shoppingCart)); + when(shoppingCartMapper.toDto(shoppingCart)).thenReturn(expected); + + //When + ShoppingCartDto actual = shoppingCartService.getByUserId(userId); + + //Then + assertEquals(expected, actual); + + verify(shoppingCartRepository, times(1)).findByUserId(anyLong()); + verify(shoppingCartMapper, times(1)).toDto(shoppingCart); + verifyNoMoreInteractions(shoppingCartMapper, shoppingCartRepository); + } + + @Test + @DisplayName("Verify EntityNotFoundException thrown with invalid user id") + void getByUserId_InvalidUserId_ThrowsEntityNotFoundException() { + //Given + Long userId = -1L; + String expected = "Can't find a shopping cart by user id: " + userId; + + when(shoppingCartRepository.findByUserId(userId)).thenReturn(Optional.empty()); + + //When + EntityNotFoundException exception = assertThrows(EntityNotFoundException.class, + () -> shoppingCartService.getShoppingCartByUserId(userId)); + + //Then + String actual = exception.getMessage(); + + assertEquals(EntityNotFoundException.class, exception.getClass()); + assertEquals(expected, actual); + + verify(shoppingCartRepository, times(1)).findByUserId(userId); + verifyNoMoreInteractions(shoppingCartRepository); + } + + @Test + @DisplayName("Verify saveBookToTheCart() method works") + void saveBookToTheCart_ValidUserIdAndCartItemCreateDto_ReturnsShoppingCartDto() { + //Given + + CartItem cartItem = getCartItem(); + + ShoppingCart shoppingCart = getShoppingCart(); + + CartItemCreateDto cartItemCreateDto = getCartItemCreateDto(); + + Book book = getBook(); + + final Long userId = 1L; + final ShoppingCartDto expected = getShoppingCartDtoFromCart(shoppingCart); + when(shoppingCartRepository.findByUserId(anyLong())).thenReturn(Optional.of(shoppingCart)); + when(bookRepository.findById(cartItemCreateDto.getBookId())).thenReturn(Optional.of(book)); + when(cartItemMapper.toEntity(cartItemCreateDto, book, shoppingCart)).thenReturn(cartItem); + when(cartItemRepository.save(cartItem)).thenReturn(cartItem); + shoppingCart.addCartItemToSet(cartItem); + when(shoppingCartMapper.toDto(shoppingCart)).thenReturn(expected); + //When + ShoppingCartDto actual = shoppingCartService + .saveBookToTheCart(userId, cartItemCreateDto); + + //Then + assertEquals(expected, actual); + assertEquals(expected.getCartItemsDto().size(), actual.getCartItemsDto().size()); + assertEquals(expected.getCartItemsDto(), actual.getCartItemsDto()); + + verify(shoppingCartRepository, times(1)).findByUserId(anyLong()); + verify(bookRepository, times(1)).findById(anyLong()); + verify(cartItemMapper, times(1)).toEntity(cartItemCreateDto, book, shoppingCart); + verify(cartItemRepository, times(1)).save(cartItem); + verify(shoppingCartMapper, times(1)).toDto(shoppingCart); + verifyNoMoreInteractions(shoppingCartRepository, + bookRepository, + cartItemMapper, + cartItemRepository, + shoppingCartMapper); + } + + @Test + @DisplayName("Verify EntityNotFoundException was thrown with invalid CartItemCreateDto") + void saveBookToTheCart_InvalidCartItemCreateDto_ThrowsEntityNotFoundException() { + //Given + ShoppingCart shoppingCart = getShoppingCart(); + + CartItemCreateDto cartItemCreateDto = getCartItemCreateDto(); + cartItemCreateDto.setBookId(-1L); + + when(shoppingCartRepository.findByUserId(anyLong())).thenReturn(Optional.of(shoppingCart)); + when(bookRepository.findById(cartItemCreateDto.getBookId())).thenReturn(Optional.empty()); + + String expected = "Can't find a book in DB by id: " + cartItemCreateDto.getBookId(); + + //When + EntityNotFoundException exception = assertThrows(EntityNotFoundException.class, + () -> shoppingCartService.saveBookToTheCart(anyLong(), cartItemCreateDto)); + + //Then + String actual = exception.getMessage(); + + assertEquals(EntityNotFoundException.class, exception.getClass()); + assertEquals(expected, actual); + + verify(shoppingCartRepository, times(1)).findByUserId(anyLong()); + verify(bookRepository, times(1)).findById(anyLong()); + verifyNoMoreInteractions(shoppingCartRepository, bookRepository); + } + + @Test + @DisplayName("Verify update() method works") + void update_ValidUserIdAndCartItemIdAndCartItemUpdateDto_UpdatesCart() { + //Given + Long cartItemId = 1L; + + CartItem cartItem = getCartItem(); + + CartItemUpdateDto cartItemUpdateDto = getCartItemUpdateDto(); + + ShoppingCart shoppingCart = getShoppingCart(); + + final ShoppingCartDto expected = getShoppingCartDtoFromCart(shoppingCart); + final Long userId = 1L; + when(cartItemRepository.findById(cartItemId)).thenReturn(Optional.of(cartItem)); + cartItem.setQuantity(cartItemUpdateDto.getQuantity()); + when(cartItemRepository.save(cartItem)).thenReturn(cartItem); + when(shoppingCartRepository.findByUserId(userId)).thenReturn(Optional.of(shoppingCart)); + when(shoppingCartMapper.toDto(shoppingCart)).thenReturn(expected); + //When + ShoppingCartDto actual = shoppingCartService.update(userId, cartItemId, cartItemUpdateDto); + //Then + assertEquals(expected, actual); + + verify(cartItemRepository, times(1)).findById(cartItemId); + verify(cartItemRepository, times(1)).save(cartItem); + verify(shoppingCartRepository, times(1)).findByUserId(userId); + verify(shoppingCartMapper, times(1)).toDto(shoppingCart); + verifyNoMoreInteractions(cartItemRepository, shoppingCartRepository, shoppingCartMapper); + } + + @Test + @DisplayName("Verify update() throws EntityNotFoundException with invalid cart item id") + void update_InvalidCartItemId_ThrowsEntityNotFoundException() { + //Given + Long userId = 1L; + Long cartItemId = -1L; + String expected = "Can't find a cart item in DB by id: " + cartItemId; + + CartItemUpdateDto cartItemUpdateDto = getCartItemUpdateDto(); + + when(cartItemRepository.findById(cartItemId)).thenReturn(Optional.empty()); + + //When + EntityNotFoundException exception = assertThrows(EntityNotFoundException.class, + () -> shoppingCartService.update(userId, cartItemId, cartItemUpdateDto)); + + //Then + String actual = exception.getMessage(); + + assertEquals(EntityNotFoundException.class, exception.getClass()); + assertEquals(expected, actual); + + verify(cartItemRepository, times(1)).findById(cartItemId); + verifyNoMoreInteractions(cartItemRepository); + } + + @Test + @DisplayName("Verify deleteCartItemFromTheCart() method works") + void deleteCartItemFromTheCart_ValidId_DeletesCartItem() { + //Given + Long cartItemId = 1L; + + when(cartItemRepository.findById(cartItemId)).thenReturn(Optional.of(new CartItem())); + + //When + shoppingCartService.deleteCartItemFromTheCart(cartItemId); + + //Then + verify(cartItemRepository, times(1)).findById(cartItemId); + verify(cartItemRepository, times(1)).deleteById(cartItemId); + verifyNoMoreInteractions(cartItemRepository); + } + + @Test + @DisplayName("Verify EntityNotFoundException thrown with invalid cart item id") + void deleteCartItemFromTheCart_InvalidId_ThrowsEntityNotFoundException() { + //Given + Long cartItemId = -1L; + String expected = "Can't delete a cart item from DB with id: " + cartItemId; + + when(cartItemRepository.findById(cartItemId)).thenReturn(Optional.empty()); + + //When + EntityNotFoundException exception = assertThrows(EntityNotFoundException.class, + () -> shoppingCartService.deleteCartItemFromTheCart(cartItemId)); + + //Then + String actual = exception.getMessage(); + + assertEquals(EntityNotFoundException.class, exception.getClass()); + assertEquals(expected, actual); + + verify(cartItemRepository, times(1)).findById(cartItemId); + verifyNoMoreInteractions(cartItemRepository); + } + + @Test + @DisplayName("Verify cleanShoppingCart() method works") + void cleanShoppingCart_ValidCart_DeletesCartItems() { + //Given + User user = getUser(); + + ShoppingCart expected = getShoppingCart(); + expected.setUser(user); + + ShoppingCart tested = getShoppingCart(); + tested.setUser(user); + tested.setCartItems(Set.of(getCartItem())); + + //When + shoppingCartService.cleanShoppingCart(tested); + + //Then + assertEquals(expected, tested); + verify(cartItemRepository, times(1)).deleteCartItemsByShoppingCartId(anyLong()); + verifyNoMoreInteractions(cartItemRepository); + } + + private ShoppingCart getShoppingCart() { + return new ShoppingCart() + .setId(1L) + .setUser(getUser()) + .setCartItems(new HashSet<>()); + } + + private User getUser() { + return new User() + .setId(1L) + .setEmail("Test Email") + .setPassword("Test Password") + .setFirstName("Name") + .setLastName("Surname") + .setShippingAddress("Address") + .setRoles(new HashSet<>()); + } + + private ShoppingCartDto getShoppingCartDtoFromCart(ShoppingCart shoppingCart) { + return new ShoppingCartDto() + .setUserId(shoppingCart.getUser().getId()) + .setCartItemsDto(new HashSet<>()); + } + + private CartItemCreateDto getCartItemCreateDto() { + return new CartItemCreateDto() + .setBookId(1L) + .setQuantity(10); + } + + private Book getBook() { + return new Book() + .setId(1L) + .setTitle("Test Book") + .setPrice(BigDecimal.TEN) + .setDescription("Test Description") + .setCoverImage("coverImage") + .setAuthor("Tester") + .setIsbn("isbn") + .setCategories(new HashSet<>()); + } + + private CartItem getCartItem() { + return new CartItem() + .setId(1L) + .setBook(getBook()) + .setShoppingCart(getShoppingCart()) + .setQuantity(10); + } + + private CartItemUpdateDto getCartItemUpdateDto() { + return new CartItemUpdateDto() + .setQuantity(20); + } +} diff --git a/src/test/resources/database/cart_items/add-test-cart-item.sql b/src/test/resources/database/cart_items/add-test-cart-item.sql new file mode 100644 index 0000000..59b6e51 --- /dev/null +++ b/src/test/resources/database/cart_items/add-test-cart-item.sql @@ -0,0 +1,2 @@ +INSERT INTO cart_items (id, shopping_cart_id, book_id, quantity) +VALUES (-1, 1, 1, 10); \ No newline at end of file diff --git a/src/test/resources/database/cart_items/delete-test-cart-item.sql b/src/test/resources/database/cart_items/delete-test-cart-item.sql new file mode 100644 index 0000000..d292037 --- /dev/null +++ b/src/test/resources/database/cart_items/delete-test-cart-item.sql @@ -0,0 +1 @@ +DELETE FROM cart_items WHERE quantity = 10; \ No newline at end of file diff --git a/src/test/resources/database/cart_items/delete-updated-cart-items.sql b/src/test/resources/database/cart_items/delete-updated-cart-items.sql new file mode 100644 index 0000000..e9f23a2 --- /dev/null +++ b/src/test/resources/database/cart_items/delete-updated-cart-items.sql @@ -0,0 +1 @@ +DELETE FROM cart_items WHERE quantity = 15; \ No newline at end of file diff --git a/src/test/resources/database/shopping_carts/add-three-default-shopping-carts.sql b/src/test/resources/database/shopping_carts/add-three-default-shopping-carts.sql new file mode 100644 index 0000000..16fc898 --- /dev/null +++ b/src/test/resources/database/shopping_carts/add-three-default-shopping-carts.sql @@ -0,0 +1,3 @@ +INSERT INTO shopping_carts (user_id) VALUES (1); +INSERT INTO shopping_carts (user_id) VALUES (2); +INSERT INTO shopping_carts (user_id) VALUES (3); \ No newline at end of file diff --git a/src/test/resources/database/shopping_carts/delete-from-shopping_carts.sql b/src/test/resources/database/shopping_carts/delete-from-shopping_carts.sql new file mode 100644 index 0000000..fa8a510 --- /dev/null +++ b/src/test/resources/database/shopping_carts/delete-from-shopping_carts.sql @@ -0,0 +1 @@ +DELETE FROM shopping_carts; \ No newline at end of file diff --git a/src/test/resources/database/users/add-three-default-users.sql b/src/test/resources/database/users/add-three-default-users.sql new file mode 100644 index 0000000..eb0b9d5 --- /dev/null +++ b/src/test/resources/database/users/add-three-default-users.sql @@ -0,0 +1,6 @@ +INSERT INTO users (id, email, password, first_name, last_name, shipping_address, is_deleted) +VALUES (1, 'email1@test.com', 'Password1', 'Name1', 'Surname1', 'Address1', false); +INSERT INTO users (id, email, password, first_name, last_name, shipping_address, is_deleted) +VALUES (2, 'email2@test.com', 'Password2', 'Name2', 'Surname2', 'Address2', false); +INSERT INTO users (id, email, password, first_name, last_name, shipping_address, is_deleted) +VALUES (3, 'email3@test.com', 'Password3', 'Name3', 'Surname3', 'Address3', false); \ No newline at end of file diff --git a/src/test/resources/database/users/delete-from-users.sql b/src/test/resources/database/users/delete-from-users.sql new file mode 100644 index 0000000..d69513f --- /dev/null +++ b/src/test/resources/database/users/delete-from-users.sql @@ -0,0 +1 @@ +DELETE FROM users; \ No newline at end of file