diff --git a/backend/src/main/java/com/woowacourse/f12/application/inventoryproduct/InventoryProductService.java b/backend/src/main/java/com/woowacourse/f12/application/inventoryproduct/InventoryProductService.java index 251e3f58c..c035ed619 100644 --- a/backend/src/main/java/com/woowacourse/f12/application/inventoryproduct/InventoryProductService.java +++ b/backend/src/main/java/com/woowacourse/f12/application/inventoryproduct/InventoryProductService.java @@ -2,14 +2,13 @@ import com.woowacourse.f12.domain.inventoryproduct.InventoryProduct; import com.woowacourse.f12.domain.inventoryproduct.InventoryProductRepository; +import com.woowacourse.f12.domain.member.Member; import com.woowacourse.f12.domain.member.MemberRepository; import com.woowacourse.f12.dto.request.inventoryproduct.ProfileProductRequest; import com.woowacourse.f12.dto.response.inventoryproduct.InventoryProductsResponse; -import com.woowacourse.f12.exception.badrequest.InvalidProfileProductException; -import com.woowacourse.f12.exception.notfound.InventoryProductNotFoundException; +import com.woowacourse.f12.exception.internalserver.SqlUpdateException; import com.woowacourse.f12.exception.notfound.MemberNotFoundException; import java.util.List; -import java.util.Objects; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -28,31 +27,19 @@ public InventoryProductService(final InventoryProductRepository inventoryProduct @Transactional public void updateProfileProducts(final Long memberId, final ProfileProductRequest profileProductRequest) { - validateMember(memberId); - validateInvalidProfileProductRequest(profileProductRequest); - updateProfileProduct(profileProductRequest); - } - - private void validateInvalidProfileProductRequest(final ProfileProductRequest profileProductRequest) { - if (Objects.isNull(profileProductRequest.getSelectedInventoryProductId()) && Objects.isNull( - profileProductRequest.getUnselectedInventoryProductId())) { - throw new InvalidProfileProductException(); - } + final Member member = memberRepository.findById(memberId) + .orElseThrow(MemberNotFoundException::new); + updateProfileProduct(member, profileProductRequest); } - private void updateProfileProduct(final ProfileProductRequest profileProductRequest) { - if (!Objects.isNull(profileProductRequest.getSelectedInventoryProductId())) { - updateProfileProduct(profileProductRequest.getSelectedInventoryProductId(), true); + private void updateProfileProduct(final Member member, final ProfileProductRequest profileProductRequest) { + final List selectedInventoryProductIds = profileProductRequest.getSelectedInventoryProductIds(); + inventoryProductRepository.updateBulkProfileProductByMember(member); + final int updateCount = inventoryProductRepository.updateBulkProfileProductByMemberAndIds(member, + selectedInventoryProductIds); + if (updateCount != selectedInventoryProductIds.size()) { + throw new SqlUpdateException(); } - if (!Objects.isNull(profileProductRequest.getUnselectedInventoryProductId())) { - updateProfileProduct(profileProductRequest.getUnselectedInventoryProductId(), false); - } - } - - private void updateProfileProduct(final Long inventoryItemId, final boolean selected) { - final InventoryProduct inventoryProduct = inventoryProductRepository.findById(inventoryItemId) - .orElseThrow(InventoryProductNotFoundException::new); - inventoryProduct.updateSelected(selected); } public InventoryProductsResponse findByMemberId(final Long memberId) { diff --git a/backend/src/main/java/com/woowacourse/f12/domain/inventoryproduct/InventoryProductRepository.java b/backend/src/main/java/com/woowacourse/f12/domain/inventoryproduct/InventoryProductRepository.java index 9980e7681..d777bf02c 100644 --- a/backend/src/main/java/com/woowacourse/f12/domain/inventoryproduct/InventoryProductRepository.java +++ b/backend/src/main/java/com/woowacourse/f12/domain/inventoryproduct/InventoryProductRepository.java @@ -4,10 +4,21 @@ import com.woowacourse.f12.domain.product.Product; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; public interface InventoryProductRepository extends JpaRepository { List findByMemberId(Long memberId); boolean existsByMemberAndProduct(Member member, Product product); + + @Modifying(clearAutomatically = true) + @Query("update InventoryProduct i set i.selected = false where i.member = :member") + int updateBulkProfileProductByMember(Member member); + + @Modifying(clearAutomatically = true) + @Query("update InventoryProduct i set i.selected = true " + + "where i.member = :member and i.id in :selectedInventoryProductIds") + int updateBulkProfileProductByMemberAndIds(Member member, List selectedInventoryProductIds); } diff --git a/backend/src/main/java/com/woowacourse/f12/dto/request/inventoryproduct/ProfileProductRequest.java b/backend/src/main/java/com/woowacourse/f12/dto/request/inventoryproduct/ProfileProductRequest.java index 8749242b5..17b1140e0 100644 --- a/backend/src/main/java/com/woowacourse/f12/dto/request/inventoryproduct/ProfileProductRequest.java +++ b/backend/src/main/java/com/woowacourse/f12/dto/request/inventoryproduct/ProfileProductRequest.java @@ -1,18 +1,19 @@ package com.woowacourse.f12.dto.request.inventoryproduct; +import java.util.List; +import javax.validation.constraints.NotNull; import lombok.Getter; @Getter public class ProfileProductRequest { - private Long selectedInventoryProductId; - private Long unselectedInventoryProductId; + @NotNull(message = "등록할 대표장비가 없습니다.") + private List selectedInventoryProductIds; private ProfileProductRequest() { } - public ProfileProductRequest(final Long selectedInventoryProductId, final Long unselectedInventoryProductId) { - this.selectedInventoryProductId = selectedInventoryProductId; - this.unselectedInventoryProductId = unselectedInventoryProductId; + public ProfileProductRequest(final List selectedInventoryProductIds) { + this.selectedInventoryProductIds = selectedInventoryProductIds; } } diff --git a/backend/src/main/java/com/woowacourse/f12/exception/internalserver/InternalServerException.java b/backend/src/main/java/com/woowacourse/f12/exception/internalserver/InternalServerException.java new file mode 100644 index 000000000..b88a7015f --- /dev/null +++ b/backend/src/main/java/com/woowacourse/f12/exception/internalserver/InternalServerException.java @@ -0,0 +1,11 @@ +package com.woowacourse.f12.exception.internalserver; + +import com.woowacourse.f12.exception.CustomException; +import com.woowacourse.f12.exception.ErrorCode; + +public class InternalServerException extends CustomException { + + public InternalServerException(final ErrorCode errorCode, final String message) { + super(errorCode, message); + } +} diff --git a/backend/src/main/java/com/woowacourse/f12/exception/internalserver/SqlUpdateException.java b/backend/src/main/java/com/woowacourse/f12/exception/internalserver/SqlUpdateException.java new file mode 100644 index 000000000..86050970a --- /dev/null +++ b/backend/src/main/java/com/woowacourse/f12/exception/internalserver/SqlUpdateException.java @@ -0,0 +1,10 @@ +package com.woowacourse.f12.exception.internalserver; + +import com.woowacourse.f12.exception.ErrorCode; + +public class SqlUpdateException extends InternalServerException { + + public SqlUpdateException() { + super(ErrorCode.INTERNAL_SERVER_ERROR, "요청된 업데이트 개수와 실행된 업데이트의 수가 다릅니다."); + } +} diff --git a/backend/src/main/java/com/woowacourse/f12/presentation/GlobalExceptionHandler.java b/backend/src/main/java/com/woowacourse/f12/presentation/GlobalExceptionHandler.java index 80bd3ef89..1a46ae159 100644 --- a/backend/src/main/java/com/woowacourse/f12/presentation/GlobalExceptionHandler.java +++ b/backend/src/main/java/com/woowacourse/f12/presentation/GlobalExceptionHandler.java @@ -5,8 +5,11 @@ import static com.woowacourse.f12.exception.ErrorCode.INVALID_SEARCH_PARAM; import com.woowacourse.f12.dto.response.ExceptionResponse; +import com.woowacourse.f12.exception.CustomException; import com.woowacourse.f12.exception.badrequest.InvalidValueException; import com.woowacourse.f12.exception.forbidden.ForbiddenMemberException; +import com.woowacourse.f12.exception.internalserver.ExternalServerException; +import com.woowacourse.f12.exception.internalserver.InternalServerException; import com.woowacourse.f12.exception.notfound.NotFoundException; import com.woowacourse.f12.exception.unauthorized.UnauthorizedException; import lombok.extern.slf4j.Slf4j; @@ -67,6 +70,11 @@ public ResponseEntity handleForbiddenMemberException(final Fo return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ExceptionResponse.from(e)); } + @ExceptionHandler({ExternalServerException.class, InternalServerException.class}) + public ResponseEntity handleInternalException(final CustomException e) { + return ResponseEntity.internalServerError().body(ExceptionResponse.from(e)); + } + @ExceptionHandler(Exception.class) public ResponseEntity handleUnhandledException(final Exception e) { log.error("[ERROR]", e); diff --git a/backend/src/main/java/com/woowacourse/f12/presentation/inventoryproduct/InventoryProductController.java b/backend/src/main/java/com/woowacourse/f12/presentation/inventoryproduct/InventoryProductController.java index a3b244b4f..c33045a07 100644 --- a/backend/src/main/java/com/woowacourse/f12/presentation/inventoryproduct/InventoryProductController.java +++ b/backend/src/main/java/com/woowacourse/f12/presentation/inventoryproduct/InventoryProductController.java @@ -5,6 +5,7 @@ import com.woowacourse.f12.dto.response.inventoryproduct.InventoryProductsResponse; import com.woowacourse.f12.presentation.auth.LoginRequired; import com.woowacourse.f12.presentation.auth.VerifiedMember; +import javax.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; @@ -25,8 +26,9 @@ public InventoryProductController(final InventoryProductService inventoryProduct @PatchMapping("/inventoryProducts") @LoginRequired - public ResponseEntity updateProfileProducts(@RequestBody final ProfileProductRequest profileProductRequest, - @VerifiedMember final Long memberId) { + public ResponseEntity updateProfileProducts( + @RequestBody @Valid final ProfileProductRequest profileProductRequest, + @VerifiedMember final Long memberId) { inventoryProductService.updateProfileProducts(memberId, profileProductRequest); return ResponseEntity.ok().build(); } diff --git a/backend/src/test/java/com/woowacourse/f12/acceptance/InventoryProductAcceptanceTest.java b/backend/src/test/java/com/woowacourse/f12/acceptance/InventoryProductAcceptanceTest.java index a4c4822bb..14a54cae0 100644 --- a/backend/src/test/java/com/woowacourse/f12/acceptance/InventoryProductAcceptanceTest.java +++ b/backend/src/test/java/com/woowacourse/f12/acceptance/InventoryProductAcceptanceTest.java @@ -69,7 +69,7 @@ class InventoryProductAcceptanceTest extends AcceptanceTest { // when ExtractableResponse profileProductResponse = 로그인된_상태로_PATCH_요청을_보낸다( "api/v1/members/inventoryProducts", token, - new ProfileProductRequest(savedInventoryProduct.getId(), null)); + new ProfileProductRequest(List.of(savedInventoryProduct.getId()))); List inventoryProductResponses = 로그인된_상태로_GET_요청을_보낸다( "/api/v1/members/inventoryProducts", @@ -83,6 +83,34 @@ class InventoryProductAcceptanceTest extends AcceptanceTest { ); } + @Test + void 대표_장비가_있는_상태에서_대표_장비를_모두_해제한다() { + // given + Product product = 제품을_저장한다(KEYBOARD_1.생성()); + LoginResponse loginResponse = 로그인을_한다(CORINNE_GITHUB.getCode()); + String token = loginResponse.getToken(); + Member member = 응답을_회원으로_변환한다(loginResponse.getMember()); + + InventoryProduct inventoryProduct = SELECTED_INVENTORY_PRODUCT.생성(member, product); + InventoryProduct savedInventoryProduct = 인벤토리에_장비를_추가한다(inventoryProduct); + + // when + ExtractableResponse profileProductResponse = 로그인된_상태로_PATCH_요청을_보낸다( + "api/v1/members/inventoryProducts", token, + new ProfileProductRequest(List.of())); + + List inventoryProductResponses = 로그인된_상태로_GET_요청을_보낸다( + "/api/v1/members/inventoryProducts", + token) + .as(InventoryProductsResponse.class).getItems(); + + // then + assertAll( + () -> assertThat(profileProductResponse.statusCode()).isEqualTo(HttpStatus.OK.value()), + () -> assertThat(inventoryProductResponses.get(0).isSelected()).isFalse() + ); + } + @Test void 등록된_장비_목록을_대표_장비를_포함해서_조회한다() { // given diff --git a/backend/src/test/java/com/woowacourse/f12/application/inventoryproduct/InventoryProductServiceTest.java b/backend/src/test/java/com/woowacourse/f12/application/inventoryproduct/InventoryProductServiceTest.java index 78ad25865..81eefbf66 100644 --- a/backend/src/test/java/com/woowacourse/f12/application/inventoryproduct/InventoryProductServiceTest.java +++ b/backend/src/test/java/com/woowacourse/f12/application/inventoryproduct/InventoryProductServiceTest.java @@ -1,9 +1,7 @@ package com.woowacourse.f12.application.inventoryproduct; import static com.woowacourse.f12.support.InventoryProductFixtures.SELECTED_INVENTORY_PRODUCT; -import static com.woowacourse.f12.support.InventoryProductFixtures.UNSELECTED_INVENTORY_PRODUCT; import static com.woowacourse.f12.support.ProductFixture.KEYBOARD_1; -import static com.woowacourse.f12.support.ProductFixture.KEYBOARD_2; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertAll; @@ -17,7 +15,7 @@ import com.woowacourse.f12.dto.request.inventoryproduct.ProfileProductRequest; import com.woowacourse.f12.dto.response.inventoryproduct.InventoryProductResponse; import com.woowacourse.f12.dto.response.inventoryproduct.InventoryProductsResponse; -import com.woowacourse.f12.exception.badrequest.InvalidProfileProductException; +import com.woowacourse.f12.exception.internalserver.SqlUpdateException; import com.woowacourse.f12.support.MemberFixtures; import java.util.List; import java.util.Optional; @@ -40,42 +38,51 @@ class InventoryProductServiceTest { private InventoryProductService inventoryProductService; @Test - void 대표_장비를_등록한다() { + void 대표_장비를_수정한다() { // given - ProfileProductRequest profileProductRequest = new ProfileProductRequest(1L, 2L); + List selectedInventoryProductIds = List.of(2L); + ProfileProductRequest profileProductRequest = new ProfileProductRequest(selectedInventoryProductIds); Member member = MemberFixtures.CORINNE.생성(1L); - InventoryProduct inventoryProduct1 = UNSELECTED_INVENTORY_PRODUCT.생성(1L, member, KEYBOARD_1.생성()); - InventoryProduct inventoryProduct2 = SELECTED_INVENTORY_PRODUCT.생성(2L, member, KEYBOARD_2.생성()); - given(memberRepository.existsById(1L)) - .willReturn(true); - given(inventoryProductRepository.findById(1L)) - .willReturn(Optional.of(inventoryProduct1)); - given(inventoryProductRepository.findById(2L)) - .willReturn(Optional.of(inventoryProduct2)); + given(memberRepository.findById(1L)) + .willReturn(Optional.of(member)); + given(inventoryProductRepository.updateBulkProfileProductByMember(member)) + .willReturn(1); + given(inventoryProductRepository.updateBulkProfileProductByMemberAndIds(member, selectedInventoryProductIds)) + .willReturn(selectedInventoryProductIds.size()); // when inventoryProductService.updateProfileProducts(1L, profileProductRequest); // then assertAll( - () -> verify(memberRepository).existsById(1L), - () -> verify(inventoryProductRepository).findById(1L), - () -> verify(inventoryProductRepository).findById(2L) + () -> verify(memberRepository).findById(1L), + () -> verify(inventoryProductRepository).updateBulkProfileProductByMember(member), + () -> verify(inventoryProductRepository).updateBulkProfileProductByMemberAndIds(member, + selectedInventoryProductIds) ); } @Test - void 대표_장비를_업데이트할_때_요청된_장비가_모두_null인_경우_예외가_발생한다() { + void 수정하려는_장비_갯수와_실제_등록된_대표_장비_갯수와_일치하지_않으면_예외를_반환한다() { // given - ProfileProductRequest profileProductRequest = new ProfileProductRequest(null, null); - given(memberRepository.existsById(1L)) - .willReturn(true); + List selectedInventoryProductIds = List.of(2L); + ProfileProductRequest profileProductRequest = new ProfileProductRequest(selectedInventoryProductIds); + Member member = MemberFixtures.CORINNE.생성(1L); + given(memberRepository.findById(1L)) + .willReturn(Optional.of(member)); + given(inventoryProductRepository.updateBulkProfileProductByMember(member)) + .willReturn(1); + given(inventoryProductRepository.updateBulkProfileProductByMemberAndIds(member, selectedInventoryProductIds)) + .willReturn(0); // when, then assertAll( () -> assertThatThrownBy(() -> inventoryProductService.updateProfileProducts(1L, profileProductRequest)) - .isExactlyInstanceOf(InvalidProfileProductException.class), - () -> verify(memberRepository).existsById(1L) + .isExactlyInstanceOf(SqlUpdateException.class), + () -> verify(memberRepository).findById(1L), + () -> verify(inventoryProductRepository).updateBulkProfileProductByMember(member), + () -> verify(inventoryProductRepository).updateBulkProfileProductByMemberAndIds(member, + selectedInventoryProductIds) ); } diff --git a/backend/src/test/java/com/woowacourse/f12/documentation/inventoryproduct/InventoryProductDocumentation.java b/backend/src/test/java/com/woowacourse/f12/documentation/inventoryproduct/InventoryProductDocumentation.java index c8967275a..edcf85dc1 100644 --- a/backend/src/test/java/com/woowacourse/f12/documentation/inventoryproduct/InventoryProductDocumentation.java +++ b/backend/src/test/java/com/woowacourse/f12/documentation/inventoryproduct/InventoryProductDocumentation.java @@ -54,7 +54,7 @@ class InventoryProductDocumentation extends Documentation { given(jwtProvider.getPayload(authorizationHeader)) .willReturn("1"); Long memberId = 1L; - ProfileProductRequest profileProductRequest = new ProfileProductRequest(1L, 2L); + ProfileProductRequest profileProductRequest = new ProfileProductRequest(List.of(1L)); willDoNothing().given(inventoryProductService).updateProfileProducts(memberId, profileProductRequest); // when diff --git a/backend/src/test/java/com/woowacourse/f12/domain/inventoryproduct/InventoryProductRepositoryTest.java b/backend/src/test/java/com/woowacourse/f12/domain/inventoryproduct/InventoryProductRepositoryTest.java index 2e369be86..323320db4 100644 --- a/backend/src/test/java/com/woowacourse/f12/domain/inventoryproduct/InventoryProductRepositoryTest.java +++ b/backend/src/test/java/com/woowacourse/f12/domain/inventoryproduct/InventoryProductRepositoryTest.java @@ -1,6 +1,7 @@ package com.woowacourse.f12.domain.inventoryproduct; import static com.woowacourse.f12.support.InventoryProductFixtures.SELECTED_INVENTORY_PRODUCT; +import static com.woowacourse.f12.support.InventoryProductFixtures.UNSELECTED_INVENTORY_PRODUCT; import static com.woowacourse.f12.support.MemberFixtures.CORINNE; import static com.woowacourse.f12.support.MemberFixtures.MINCHO; import static com.woowacourse.f12.support.ProductFixture.KEYBOARD_1; @@ -64,6 +65,37 @@ class InventoryProductRepositoryTest { assertThat(actual).isTrue(); } + @Test + void 인벤토리_상품_모두를_대표_장비에서_해제한다() { + // given + Member member = 회원을_저장한다(CORINNE.생성()); + Product product = 제품을_저장한다(KEYBOARD_1.생성(1L)); + InventoryProduct inventoryProduct = UNSELECTED_INVENTORY_PRODUCT.생성(member, product); + inventoryProductRepository.save(inventoryProduct); + + // when + int actual = inventoryProductRepository.updateBulkProfileProductByMember(member); + + // then + assertThat(actual).isOne(); + } + + @Test + void 인벤토리_상품을_대표_장비로_등록한다() { + // given + Member member = 회원을_저장한다(CORINNE.생성()); + Product product = 제품을_저장한다(KEYBOARD_1.생성(1L)); + InventoryProduct inventoryProduct = UNSELECTED_INVENTORY_PRODUCT.생성(member, product); + inventoryProductRepository.save(inventoryProduct); + + // when + int actual = inventoryProductRepository.updateBulkProfileProductByMemberAndIds(member, + List.of(inventoryProduct.getId())); + + // then + assertThat(actual).isOne(); + } + private Product 제품을_저장한다(Product product) { return productRepository.save(product); } diff --git a/backend/src/test/java/com/woowacourse/f12/presentation/inventoryproduct/InventoryProductControllerTest.java b/backend/src/test/java/com/woowacourse/f12/presentation/inventoryproduct/InventoryProductControllerTest.java index 91f5e206b..946959b1e 100644 --- a/backend/src/test/java/com/woowacourse/f12/presentation/inventoryproduct/InventoryProductControllerTest.java +++ b/backend/src/test/java/com/woowacourse/f12/presentation/inventoryproduct/InventoryProductControllerTest.java @@ -8,6 +8,7 @@ import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.willDoNothing; import static org.mockito.BDDMockito.willThrow; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; @@ -21,7 +22,6 @@ import com.woowacourse.f12.domain.member.Member; import com.woowacourse.f12.dto.request.inventoryproduct.ProfileProductRequest; import com.woowacourse.f12.dto.response.inventoryproduct.InventoryProductsResponse; -import com.woowacourse.f12.exception.badrequest.InvalidProfileProductException; import com.woowacourse.f12.exception.notfound.InventoryProductNotFoundException; import com.woowacourse.f12.support.MemberFixtures; import java.util.List; @@ -55,7 +55,7 @@ class InventoryProductControllerTest { .willReturn(true); given(jwtProvider.getPayload(authorizationHeader)) .willReturn("1"); - ProfileProductRequest profileProductRequest = new ProfileProductRequest(1L, 2L); + ProfileProductRequest profileProductRequest = new ProfileProductRequest(List.of(1L)); willDoNothing().given(inventoryProductService).updateProfileProducts(1L, profileProductRequest); // when @@ -84,7 +84,7 @@ class InventoryProductControllerTest { .willReturn(true); given(jwtProvider.getPayload(authorizationHeader)) .willReturn("1"); - ProfileProductRequest profileProductRequest = new ProfileProductRequest(1L, 2L); + ProfileProductRequest profileProductRequest = new ProfileProductRequest(List.of(1L)); willThrow(new InventoryProductNotFoundException()).given(inventoryProductService) .updateProfileProducts(anyLong(), any(ProfileProductRequest.class)); @@ -112,11 +112,7 @@ class InventoryProductControllerTest { String authorizationHeader = "Bearer Token"; given(jwtProvider.validateToken(authorizationHeader)) .willReturn(true); - given(jwtProvider.getPayload(authorizationHeader)) - .willReturn("1"); - ProfileProductRequest profileProductRequest = new ProfileProductRequest(null, null); - willThrow(new InvalidProfileProductException()).given(inventoryProductService) - .updateProfileProducts(anyLong(), any(ProfileProductRequest.class)); + ProfileProductRequest profileProductRequest = new ProfileProductRequest(null); // when mockMvc.perform( @@ -131,8 +127,9 @@ class InventoryProductControllerTest { // then assertAll( () -> verify(jwtProvider).validateToken(authorizationHeader), - () -> verify(jwtProvider).getPayload(authorizationHeader), - () -> verify(inventoryProductService).updateProfileProducts(anyLong(), any(ProfileProductRequest.class)) + () -> verify(jwtProvider, times(0)).getPayload(authorizationHeader), + () -> verify(inventoryProductService, times(0)).updateProfileProducts(anyLong(), + any(ProfileProductRequest.class)) ); }