diff --git a/src/main/kotlin/org/store/clothstar/kakaoLogin/controller/KakaoController.kt b/src/main/kotlin/org/store/clothstar/kakaoLogin/controller/KakaoController.kt index 7b6772a..d576b28 100644 --- a/src/main/kotlin/org/store/clothstar/kakaoLogin/controller/KakaoController.kt +++ b/src/main/kotlin/org/store/clothstar/kakaoLogin/controller/KakaoController.kt @@ -4,8 +4,6 @@ import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController -import org.store.clothstar.kakaoLogin.dto.KakaoRenewTokenResponseDto -import org.store.clothstar.kakaoLogin.dto.KakaoTokenInfoResponseDto import org.store.clothstar.kakaoLogin.service.KakaoLoginService @RestController @@ -17,21 +15,4 @@ class KakaoController( fun kakaoCallback(@RequestParam code: String): ResponseEntity { return ResponseEntity.ok(code) } - - // 토큰 정보 확인 - @GetMapping("/auth/kakao/accessInfo") - fun getAccessInfo(@RequestParam accessToken: String): KakaoTokenInfoResponseDto { - val tokenInfo = kakaoLoginService.getTokenInfo(accessToken) - return tokenInfo - } - - // 액세스 토큰 갱신 - 유효성 검사 후 토큰 유효기간 만료 시 재로그인 요청 - @GetMapping("/auth/kakao/check") - fun checkToken( - @RequestParam accessToken: String, - @RequestParam refreshToken: String - ): ResponseEntity { - val renewTokenInfo: KakaoRenewTokenResponseDto = kakaoLoginService.validateToken(accessToken, refreshToken) - return ResponseEntity.ok(renewTokenInfo) - } } \ No newline at end of file diff --git a/src/main/kotlin/org/store/clothstar/kakaoLogin/dto/KakaoRenewTokenResponseDto.kt b/src/main/kotlin/org/store/clothstar/kakaoLogin/dto/KakaoRenewTokenResponseDto.kt deleted file mode 100644 index be9eae9..0000000 --- a/src/main/kotlin/org/store/clothstar/kakaoLogin/dto/KakaoRenewTokenResponseDto.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.store.clothstar.kakaoLogin.dto - -import com.fasterxml.jackson.annotation.JsonProperty - -class KakaoRenewTokenResponseDto { - // 토큰 타입, bearer로 고정 - @JsonProperty("token_type") - private val tokenType: String? = null - - // 갱신된 사용자 액세스 토큰 값 - @JsonProperty("access_token") - val accessToken: String? = null - - // 액세스 토큰 만료 시간(초) - @JsonProperty("expires_in") - val expiresIn: Int? = null -} \ No newline at end of file diff --git a/src/main/kotlin/org/store/clothstar/kakaoLogin/dto/KakaoTokenInfoResponseDto.kt b/src/main/kotlin/org/store/clothstar/kakaoLogin/dto/KakaoTokenInfoResponseDto.kt deleted file mode 100644 index 4e5bfb6..0000000 --- a/src/main/kotlin/org/store/clothstar/kakaoLogin/dto/KakaoTokenInfoResponseDto.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.store.clothstar.kakaoLogin.dto - -import com.fasterxml.jackson.annotation.JsonProperty - -class KakaoTokenInfoResponseDto { - // 액세스 토큰 만료 시간(밀리초) - @JsonProperty("expiresInMillis") - private val expiresInMillis: Int? = null - - // 회원번호 - @JsonProperty("id") - private val id: String? = null - - // 액세스 토큰 만료 시간(초) - @JsonProperty("expires_in") - val expiresIn: Int? = null - - // 앱 아이디 - @JsonProperty("app_id") - val appId: Int? = null - - // 앱 아이디 - @JsonProperty("appId") - val appIdd: Int? = null -} \ No newline at end of file diff --git a/src/main/kotlin/org/store/clothstar/kakaoLogin/dto/TokenUserInfoResponseDto.kt b/src/main/kotlin/org/store/clothstar/kakaoLogin/dto/TokenUserInfoResponseDto.kt deleted file mode 100644 index 8c7b47d..0000000 --- a/src/main/kotlin/org/store/clothstar/kakaoLogin/dto/TokenUserInfoResponseDto.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.store.clothstar.kakaoLogin.dto - -class TokenUserInfoResponseDto( - val accessToken: KakaoTokenResponseDto, - val userInfo: KakaoUserInfoResponseDto -) \ No newline at end of file diff --git a/src/main/kotlin/org/store/clothstar/kakaoLogin/service/KakaoLoginService.kt b/src/main/kotlin/org/store/clothstar/kakaoLogin/service/KakaoLoginService.kt index 892c9b3..512257b 100644 --- a/src/main/kotlin/org/store/clothstar/kakaoLogin/service/KakaoLoginService.kt +++ b/src/main/kotlin/org/store/clothstar/kakaoLogin/service/KakaoLoginService.kt @@ -9,8 +9,6 @@ import org.springframework.util.LinkedMultiValueMap import org.springframework.util.MultiValueMap import org.springframework.web.reactive.function.BodyInserters import org.springframework.web.reactive.function.client.WebClient -import org.store.clothstar.kakaoLogin.dto.KakaoRenewTokenResponseDto -import org.store.clothstar.kakaoLogin.dto.KakaoTokenInfoResponseDto import org.store.clothstar.kakaoLogin.dto.KakaoTokenResponseDto import org.store.clothstar.kakaoLogin.dto.KakaoUserInfoResponseDto @@ -86,59 +84,4 @@ class KakaoLoginService { logger.info { "email : ${userInfo.kakaoAccount!!.email}" } return userInfo } - - // 토큰 유효성 검사 - fun validateToken(accessToken: String, refreshToken: String): KakaoRenewTokenResponseDto { - return try { - getTokenInfo(accessToken) - // 액세스 토큰이 유효한 경우 토큰 갱신 - refreshAccessToken(refreshToken) - } catch (e: Exception) { - // getTokenInfo에서 예외가 발생한 경우 재로그인 필요 - throw Exception("Access Token이 만료되었습니다. 재로그인이 필요합니다.") - } - } - - // 토큰 정보 보기 - fun getTokenInfo(accessToken: String): KakaoTokenInfoResponseDto { - val response = WebClient.create("https://kapi.kakao.com") - .get() - .uri("/v1/user/access_token_info") - .header("Authorization", "Bearer $accessToken") - .retrieve() - .bodyToMono(String::class.java) - .block() - - val objectMapper = ObjectMapper() - val tokenInfo: KakaoTokenInfoResponseDto = - objectMapper.readValue(response, KakaoTokenInfoResponseDto::class.java) - - logger.info { "Access Token 만료기한 : ${tokenInfo.expiresIn}" } - return tokenInfo - } - - // 리프레시 토큰으로 액세스 토큰 갱신 - fun refreshAccessToken(refreshToken: String): KakaoRenewTokenResponseDto { - val params: MultiValueMap = LinkedMultiValueMap() - params.add("grant_type", "refresh_token") - params.add("client_id", clientId) - params.add("refresh_token", refreshToken) - params.add("client_secret", clientSecret) - - val response = WebClient.create("https://kauth.kakao.com") - .post() - .uri(tokenUri) - .body(BodyInserters.fromFormData(params)) - .header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8") - .retrieve() - .bodyToMono(String::class.java) - .block() - - val objectMapper = ObjectMapper() - val kakaoToken: KakaoRenewTokenResponseDto = - objectMapper.readValue(response, KakaoRenewTokenResponseDto::class.java) - - logger.info { "갱신된 Access Token : ${kakaoToken.accessToken}" } - return kakaoToken - } } \ No newline at end of file diff --git a/src/test/kotlin/org/store/clothstar/member/authentication/controller/AuthenticationControllerTest.kt b/src/test/kotlin/org/store/clothstar/member/authentication/controller/AuthenticationControllerTest.kt index ef18e54..4b7b8b4 100644 --- a/src/test/kotlin/org/store/clothstar/member/authentication/controller/AuthenticationControllerTest.kt +++ b/src/test/kotlin/org/store/clothstar/member/authentication/controller/AuthenticationControllerTest.kt @@ -3,8 +3,10 @@ package org.store.clothstar.member.authentication.controller import com.fasterxml.jackson.databind.ObjectMapper import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer +import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest @@ -12,9 +14,12 @@ import org.springframework.http.MediaType import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.* import org.springframework.transaction.annotation.Transactional import org.store.clothstar.common.config.redis.RedisUtil +import org.store.clothstar.common.error.ErrorCode +import org.store.clothstar.common.error.exception.InvalidSignupMemberRequest +import org.store.clothstar.common.error.exception.order.OrderNotFoundException import org.store.clothstar.kakaoLogin.service.KakaoLoginService import org.store.clothstar.member.authentication.domain.SignUpType import org.store.clothstar.member.dto.request.KakaoMemberRequest @@ -145,4 +150,58 @@ class AuthenticationControllerTest( mockWebServer.shutdown() } + + @DisplayName("멤버 카카오 회원가입에서 요청DTO가 NULL일 경우 에러처리 테스트") + @Test + fun normalSignUpExceptionTest() { + //kakaoMemberRequest 요청 DTO 생성 + val kakaoMemberRequest = KakaoMemberRequest( + name = "Test User", + telNo = "010-1234-5678", + email = null, + code = "test_code" + ) + + // kakaoMemberRequest를 null로 맞춤 + val signUpRequest = SignUpRequest(null, kakaoMemberRequest) + val requestBody = objectMapper.writeValueAsString(signUpRequest) + + //when & then + mockMvc.perform( + post(MEMBER_URL) + .param("signUpType", SignUpType.NORMAL.toString()) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + ) + .andExpect(status().isBadRequest) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.errorCode").value(400)) + .andExpect(jsonPath("$.message").value("회원가입 시 회원 정보가 필요합니다.")) + } + + @DisplayName("멤버 카카오 회원가입에서 요청DTO가 NULL일 경우 에러처리 테스트") + @Test + fun kakaoSignUpExceptionTest() { + // createMemberRequest 생성을 위한 이메일과 인증번호로 redis 데이터 생성 + val email = "test@naver.com" + val certifyNum = redisUtil.createdCertifyNum() + redisUtil.createRedisData(email, certifyNum) + + // kakaoMemberRequest를 null로 맞춤 + val createMemberRequest = CreateObject.getCreateMemberRequest(email, certifyNum) + val signUpRequest = SignUpRequest(createMemberRequest, null) + val requestBody = objectMapper.writeValueAsString(signUpRequest) + + //when & then + mockMvc.perform( + post(MEMBER_URL) + .param("signUpType", SignUpType.KAKAO.toString()) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + ) + .andExpect(status().isBadRequest) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.errorCode").value(400)) + .andExpect(jsonPath("$.message").value("회원가입 시 회원 정보가 필요합니다.")) + } } \ No newline at end of file diff --git a/src/test/kotlin/org/store/clothstar/order/OrderUserIntegrationTest.kt b/src/test/kotlin/org/store/clothstar/order/OrderUserIntegrationTest.kt index 3556625..67ef3a2 100644 --- a/src/test/kotlin/org/store/clothstar/order/OrderUserIntegrationTest.kt +++ b/src/test/kotlin/org/store/clothstar/order/OrderUserIntegrationTest.kt @@ -1,6 +1,8 @@ package org.store.clothstar.order import com.fasterxml.jackson.databind.ObjectMapper +import io.mockk.every +import io.mockk.mockk import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test @@ -13,8 +15,7 @@ import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc import org.springframework.test.web.servlet.ResultActions import org.springframework.test.web.servlet.request.MockMvcRequestBuilders -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status +import org.springframework.test.web.servlet.result.MockMvcResultMatchers.* import org.springframework.transaction.annotation.Transactional import org.store.clothstar.category.repository.CategoryJpaRepository import org.store.clothstar.member.domain.Member @@ -33,6 +34,9 @@ import org.store.clothstar.order.dto.request.OrderRequestWrapper import org.store.clothstar.order.repository.OrderDetailRepository import org.store.clothstar.order.repository.OrderRepository import org.store.clothstar.order.util.CreateOrderObject +import org.store.clothstar.product.domain.Item +import org.store.clothstar.product.domain.type.DisplayStatus +import org.store.clothstar.product.domain.type.SaleStatus import org.store.clothstar.product.repository.ItemRepository import org.store.clothstar.product.repository.ProductRepository import java.time.LocalDateTime @@ -198,6 +202,82 @@ class OrderUserIntegrationTest( assertEquals(1, savedOrder.orderDetails.size) } + @Test + @DisplayName("주문 생성시 상품재고가 0일경우 에러처리 테스트") + fun testCreateOrder_itemStockZeroException() { + //given + val member: Member = memberRepository.save(CreateOrderObject.getMember()) + val address = addressRepository.save(CreateOrderObject.getAddress(member)) + val category = categoryRepository.save(CreateOrderObject.getCategory()) + sellerRepository.save(CreateOrderObject.getSeller(member)) + val product = productRepository.save(CreateOrderObject.getProduct(member, category)) + val item = itemRepository.save(CreateOrderObject.getItem(product)).apply { + stock = 0 + } + + val createOrderRequest = CreateOrderRequest( + paymentMethod = PaymentMethod.CARD, + memberId = member.memberId!!, + addressId = address.addressId!! + ) + val createOrderDetailRequest = CreateOrderDetailRequest( + productId = product.productId!!, + itemId = item.itemId!!, + quantity = 1 + ) + val orderRequestWrapper = OrderRequestWrapper(createOrderRequest, createOrderDetailRequest) + val requestBody = objectMapper.writeValueAsString(orderRequestWrapper) + + //when & then + val actions: ResultActions = mockMvc.perform( + MockMvcRequestBuilders.post(ORDER_URL) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + ) + .andExpect(status().isBadRequest) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.errorCode").value(400)) + .andExpect(jsonPath("$.message").value("품절된 상품입니다.")) + } + + @Test + @DisplayName("주문 생성시, 주문개수가 상품재고보다 많을 때 재고 부족 예외처리 테스트") + fun testCreateOrder_InsufficientStock_Exception() { + //given + val member: Member = memberRepository.save(CreateOrderObject.getMember()) + val address = addressRepository.save(CreateOrderObject.getAddress(member)) + val category = categoryRepository.save(CreateOrderObject.getCategory()) + sellerRepository.save(CreateOrderObject.getSeller(member)) + val product = productRepository.save(CreateOrderObject.getProduct(member, category)) + val item = itemRepository.save(CreateOrderObject.getItem(product)).apply { + stock = 1 + } + + val createOrderRequest = CreateOrderRequest( + paymentMethod = PaymentMethod.CARD, + memberId = member.memberId!!, + addressId = address.addressId!! + ) + val createOrderDetailRequest = CreateOrderDetailRequest( + productId = product.productId!!, + itemId = item.itemId!!, + quantity = 5 + ) + val orderRequestWrapper = OrderRequestWrapper(createOrderRequest, createOrderDetailRequest) + val requestBody = objectMapper.writeValueAsString(orderRequestWrapper) + + //when & then + val actions: ResultActions = mockMvc.perform( + MockMvcRequestBuilders.post(ORDER_URL) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody) + ) + .andExpect(status().isBadRequest) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.errorCode").value(400)) + .andExpect(jsonPath("$.message").value("주문 개수가 상품 재고보다 더 많아 요청을 처리할 수 없습니다.")) + } + @Test @DisplayName("주문상세 추가") fun testAddOrderDetail() { diff --git a/src/test/kotlin/org/store/clothstar/order/service/OrderSellerServiceTest.kt b/src/test/kotlin/org/store/clothstar/order/service/OrderSellerServiceTest.kt index 45860f4..dc43454 100644 --- a/src/test/kotlin/org/store/clothstar/order/service/OrderSellerServiceTest.kt +++ b/src/test/kotlin/org/store/clothstar/order/service/OrderSellerServiceTest.kt @@ -5,6 +5,7 @@ import io.mockk.impl.annotations.InjectMockKs import io.mockk.impl.annotations.MockK import io.mockk.junit5.MockKExtension import io.mockk.justRun +import io.mockk.mockk import io.mockk.verify import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Assertions.assertEquals @@ -12,6 +13,8 @@ import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.extension.ExtendWith import org.springframework.data.repository.findByIdOrNull +import org.springframework.http.HttpStatus +import org.springframework.web.server.ResponseStatusException import org.store.clothstar.common.error.ErrorCode import org.store.clothstar.common.error.exception.order.OrderNotFoundException import org.store.clothstar.member.domain.Address @@ -56,92 +59,85 @@ class OrderSellerServiceTest { @MockK lateinit var productService: ProductService - @MockK - lateinit var order: Order - - @MockK - lateinit var member: Member + // 판매자 주문(CONFIRMED) 리스트 조회 + @Test + @DisplayName("판매자 주문(CONFIRMED) 리스트 조회 - 성공 테스트") + fun addOrderDetail_success_test() { + // Mock 객체 생성 및 설정 + val orderPrice = mockk { + every { fixedPrice } returns 10000 + every { oneKindTotalPrice } returns 10000 + } - @MockK - lateinit var seller: Seller + val orderDetail = mockk { + every { price } returns orderPrice + every { quantity } returns 1 + every { orderDetailId } returns 1L + every { deletedAt } returns null + every { itemId } returns 1L + every { productId } returns 1L + } - @MockK - lateinit var address: Address + val item = mockk { + every { itemId } returns 1L + every { name } returns "상품옵션이름" + every { finalPrice } returns 10000 + } - @MockK - lateinit var product: Product + val product = mockk { + every { productId } returns 1L + every { name } returns "상품이름" + every { price } returns 1000 + } - @MockK - lateinit var item: Item + val member = mockk { + every { name } returns "수빈" + } - @MockK - lateinit var addressInfo: AddressInfo + val orderAddressInfo = mockk { + every { addressBasic } returns "address1" + every { addressDetail } returns "address2" + } - @MockK - lateinit var totalPrice: TotalPrice + val address = mockk
{ + every { addressInfo } returns orderAddressInfo + every { receiverName } returns "수빈" + every { telNo } returns "010-1111-1111" + every { deliveryRequest } returns "문앞" + } - @MockK - lateinit var price: Price + val seller = mockk { + every { brandName } returns "brandName" + } - @MockK - lateinit var orderDetail: OrderDetail + val orderTotalPrice = mockk { + every { shipping } returns 3000 + every { products } returns 5000 + every { payment } returns 8000 + } - val orderId = "4b1a17b5-45f0-455a-a5e3-2c863de18b05" - val memberId = 1L - val addressId = 2L - val productId = 3L - val itemId = 4L + val order = mockk { + every { orderId } returns "4b1a17b5-45f0-455a-a5e3-2c863de18b05" + every { memberId } returns 1L + every { addressId } returns 1L + every { createdAt } returns LocalDateTime.now() + every { status } returns Status.CONFIRMED + every { paymentMethod } returns PaymentMethod.CARD + every { totalPrice } returns orderTotalPrice + every { orderDetails } returns mutableListOf(orderDetail) + } - // 판매자 주문(CONFIRMED) 리스트 조회 - @Test - @DisplayName("판매자 주문(CONFIRMED) 리스트 조회 - 성공 테스트") - fun addOrderDetail_success_test() { //given every { orderRepository.findConfirmedAndNotDeletedOrders() } returns listOf(order) - every { order.memberId } returns memberId - every { order.addressId } returns addressId - every { memberService.getMemberByMemberId(memberId) } returns member - every { addressService.getAddressById(addressId) } returns address - every { sellerService.getSellerById(memberId) } returns seller - - every { totalPrice.shipping } returns 3000 - every { totalPrice.products } returns 5000 - every { totalPrice.payment } returns 8000 - every { order.orderId } returns orderId - every { member.name } returns "수빈" - every { order.createdAt } returns LocalDateTime.now() - every { order.status } returns Status.CONFIRMED - every { order.paymentMethod } returns PaymentMethod.CARD - every { order.totalPrice } returns totalPrice - every { address.addressInfo } returns addressInfo - every { address.receiverName } returns "수빈" - every { addressInfo.addressBasic } returns "address1" - every { addressInfo.addressDetail } returns "address2" - every { address.telNo } returns "010-1111-1111" - every { address.deliveryRequest } returns "문앞" + every { memberService.getMemberByMemberId(any()) } returns member + every { addressService.getAddressById(any()) } returns address + every { sellerService.getSellerById(any()) } returns seller val expectedorderResponse = OrderResponse.from(order, member, address) - every { order.orderDetails } returns mutableListOf(orderDetail) - every { orderDetail.deletedAt } returns null // productIds, itemIds로부터 Product/Item 리스트 가져오기 - every { orderDetail.itemId } returns itemId - every { orderDetail.productId } returns productId - every { productService.findByProductIdIn(listOf(productId)) } returns listOf(product) - every { itemService.findByIdIn(listOf(itemId)) } returns listOf(item) - - every { item.itemId } returns itemId - every { product.productId } returns productId - - every { orderDetail.orderDetailId } returns 1L - every { product.name } returns "상품이름" - every { item.name } returns "상품옵션이름" - every { seller.brandName } returns "brandName" - every { product.price } returns 1000 - every { orderDetail.quantity } returns 1 - every { orderDetail.price } returns price - every { item.finalPrice } returns 10000 - every { price.oneKindTotalPrice } returns 10000 + every { productService.findByProductIdIn(any()) } returns listOf(product) + every { itemService.findByIdIn(any()) } returns listOf(item) // 주문상세 DTO 리스트 만들기 val orderDetailDTOs = listOf(OrderDetailDTO.from(orderDetail, item, product, seller.brandName)) @@ -155,11 +151,185 @@ class OrderSellerServiceTest { //then assertThat(orderReponse).usingRecursiveComparison().isEqualTo(listOf(expectedorderResponse)) verify(exactly = 1) { orderRepository.findConfirmedAndNotDeletedOrders() } - verify(exactly = 1) { memberService.getMemberByMemberId(memberId) } - verify(exactly = 1) { addressService.getAddressById(addressId) } - verify(exactly = 1) { sellerService.getSellerById(memberId) } - verify(exactly = 1) { productService.findByProductIdIn(listOf(productId)) } - verify(exactly = 1) { itemService.findByIdIn(listOf(itemId)) } + verify(exactly = 1) { memberService.getMemberByMemberId(any()) } + verify(exactly = 1) { addressService.getAddressById(any()) } + verify(exactly = 1) { sellerService.getSellerById(any()) } + verify(exactly = 1) { productService.findByProductIdIn(any()) } + verify(exactly = 1) { itemService.findByIdIn(any()) } + } + + @Test + @DisplayName("판매자 주문(CONFIRMED) 리스트 조회 - productId가 NULL일 경우 예외처리 테스트") + fun addOrderDetail_productIdNullException_test() { + // Mock 객체 생성 및 설정 + val orderPrice = mockk { + every { fixedPrice } returns 10000 + every { oneKindTotalPrice } returns 10000 + } + + val orderDetail = mockk { + every { price } returns orderPrice + every { quantity } returns 1 + every { orderDetailId } returns 1L + every { deletedAt } returns null + every { itemId } returns 1L + every { productId } returns 1L + } + + val item = mockk { + every { itemId } returns 1L + every { name } returns "상품옵션이름" + every { finalPrice } returns 10000 + } + + val product = mockk { + every { productId } returns 1L + every { name } returns "상품이름" + every { price } returns 1000 + } + + val member = mockk { + every { name } returns "수빈" + } + + val orderAddressInfo = mockk { + every { addressBasic } returns "address1" + every { addressDetail } returns "address2" + } + + val address = mockk
{ + every { addressInfo } returns orderAddressInfo + every { receiverName } returns "수빈" + every { telNo } returns "010-1111-1111" + every { deliveryRequest } returns "문앞" + } + + val seller = mockk { + every { brandName } returns "brandName" + } + + val orderTotalPrice = mockk { + every { shipping } returns 3000 + every { products } returns 5000 + every { payment } returns 8000 + } + + val order = mockk { + every { orderId } returns "4b1a17b5-45f0-455a-a5e3-2c863de18b05" + every { memberId } returns 1L + every { addressId } returns 1L + every { createdAt } returns LocalDateTime.now() + every { status } returns Status.CONFIRMED + every { paymentMethod } returns PaymentMethod.CARD + every { totalPrice } returns orderTotalPrice + every { orderDetails } returns mutableListOf(orderDetail) + } + + //given + every { orderRepository.findConfirmedAndNotDeletedOrders() } returns listOf(order) + every { memberService.getMemberByMemberId(any()) } returns member + every { addressService.getAddressById(any()) } returns address + every { sellerService.getSellerById(any()) } returns seller + + //`productService.findByProductIdIn()` 호출 시 빈 리스트 반환 설정 + every { productService.findByProductIdIn(any()) } returns listOf() + every { itemService.findByIdIn(any()) } returns listOf() + + //when + val exception = assertThrows { + orderSellerService.getConfirmedOrders() + } + + //then + assertThat(exception.statusCode).isEqualTo(HttpStatus.NOT_FOUND) + assertThat(exception.reason).isEqualTo("Product not found") + } + + @Test + @DisplayName("판매자 주문(CONFIRMED) 리스트 조회 - itemId가 NULL일 경우 예외처리 테스트") + fun addOrderDetail_itemIdNullException_test() { + // Mock 객체 생성 및 설정 + val orderPrice = mockk { + every { fixedPrice } returns 10000 + every { oneKindTotalPrice } returns 10000 + } + + val orderDetail = mockk { + every { price } returns orderPrice + every { quantity } returns 1 + every { orderDetailId } returns 1L + every { deletedAt } returns null + every { itemId } returns 1L + every { productId } returns 1L + } + + val item = mockk { + every { itemId } returns 1L + every { name } returns "상품옵션이름" + every { finalPrice } returns 10000 + } + + val product = mockk { + every { productId } returns 1L + every { name } returns "상품이름" + every { price } returns 1000 + } + + val member = mockk { + every { name } returns "수빈" + } + + val orderAddressInfo = mockk { + every { addressBasic } returns "address1" + every { addressDetail } returns "address2" + } + + val address = mockk
{ + every { addressInfo } returns orderAddressInfo + every { receiverName } returns "수빈" + every { telNo } returns "010-1111-1111" + every { deliveryRequest } returns "문앞" + } + + val seller = mockk { + every { brandName } returns "brandName" + } + + val orderTotalPrice = mockk { + every { shipping } returns 3000 + every { products } returns 5000 + every { payment } returns 8000 + } + + val order = mockk { + every { orderId } returns "4b1a17b5-45f0-455a-a5e3-2c863de18b05" + every { memberId } returns 1L + every { addressId } returns 1L + every { createdAt } returns LocalDateTime.now() + every { status } returns Status.CONFIRMED + every { paymentMethod } returns PaymentMethod.CARD + every { totalPrice } returns orderTotalPrice + every { orderDetails } returns mutableListOf(orderDetail) + } + + //given + every { orderRepository.findConfirmedAndNotDeletedOrders() } returns listOf(order) + every { memberService.getMemberByMemberId(any()) } returns member + every { addressService.getAddressById(any()) } returns address + every { sellerService.getSellerById(any()) } returns seller + + //`itemService.findByIdIn()` 호출 시 빈 리스트 반환 설정 + every { productService.findByProductIdIn(any()) } returns listOf(product) + every { itemService.findByIdIn(any()) } returns listOf() + + //when + val exception = assertThrows { + orderSellerService.getConfirmedOrders() + } + + //then + assertThat(exception.statusCode).isEqualTo(HttpStatus.NOT_FOUND) + assertThat(exception.reason).isEqualTo("Item not found") } // 판매자 주문 승인 - approveOrder @@ -167,18 +337,20 @@ class OrderSellerServiceTest { @DisplayName("판매자 주문 승인 - 성공 테스트") fun approveOrder_success_test() { //given - every { order.status } returns Status.CONFIRMED - every { orderRepository.findByIdOrNull(orderId) } returns order + val order = mockk { + every { status } returns Status.CONFIRMED + } + every { orderRepository.findByIdOrNull(any()) } returns order justRun { order.validateForStatusCONFIRMEDAndDeletedAt() } every { order.updateStatus(Status.PROCESSING) } answers { every { order.status } returns Status.PROCESSING } //when - orderSellerService.approveOrder(orderId) + orderSellerService.approveOrder("4b1a17b5-45f0-455a-a5e3-2c863de18b05") //then - verify(exactly = 1) { orderRepository.findByIdOrNull(orderId) } + verify(exactly = 1) { orderRepository.findByIdOrNull(any()) } verify(exactly = 1) { order.validateForStatusCONFIRMEDAndDeletedAt() } verify(exactly = 1) { order.updateStatus(Status.PROCESSING) } assertEquals(Status.PROCESSING, order.status) @@ -188,12 +360,14 @@ class OrderSellerServiceTest { @DisplayName("판매자 주문 승인 - 주문번호가 존재하지 않을 때 예외처리 테스트") fun approveOrder_orderNotFound_exception_test() { //given - every { order.status } returns Status.CONFIRMED - every { orderRepository.findByIdOrNull(orderId) } returns null + val order = mockk { + every { status } returns Status.CONFIRMED + } + every { orderRepository.findByIdOrNull(any()) } returns null //when & then val exception = assertThrows { - orderSellerService.approveOrder(orderId) + orderSellerService.approveOrder("4b1a17b5-45f0-455a-a5e3-2c863de18b05") } assertEquals(ErrorCode.NOT_FOUND_ORDER, exception.errorCode) } @@ -203,18 +377,20 @@ class OrderSellerServiceTest { @DisplayName("판매자 주문 취소 - 성공 테스트") fun cancelOrder_success_test() { //given - every { order.status } returns Status.CONFIRMED - every { orderRepository.findByIdOrNull(orderId) } returns order + val order = mockk { + every { status } returns Status.CONFIRMED + } + every { orderRepository.findByIdOrNull(any()) } returns order justRun { order.validateForStatusCONFIRMEDAndDeletedAt() } every { order.updateStatus(Status.CANCELED) } answers { every { order.status } returns Status.CANCELED } //when - orderSellerService.cancelOrder(orderId) + orderSellerService.cancelOrder("4b1a17b5-45f0-455a-a5e3-2c863de18b05") //then - verify(exactly = 1) { orderRepository.findByIdOrNull(orderId) } + verify(exactly = 1) { orderRepository.findByIdOrNull(any()) } verify(exactly = 1) { order.validateForStatusCONFIRMEDAndDeletedAt() } verify(exactly = 1) { order.updateStatus(Status.CANCELED) } assertEquals(Status.CANCELED, order.status) @@ -224,12 +400,14 @@ class OrderSellerServiceTest { @DisplayName("판매자 주문 취소 - 주문번호가 존재하지 않을 때 예외처리 테스트") fun cancelOrder_orderNotFound_exception_test() { //given - every { order.status } returns Status.CONFIRMED - every { orderRepository.findByIdOrNull(orderId) } returns null + val order = mockk { + every { status } returns Status.CONFIRMED + } + every { orderRepository.findByIdOrNull(any()) } returns null //when & then val exception = assertThrows { - orderSellerService.cancelOrder(orderId) + orderSellerService.cancelOrder("4b1a17b5-45f0-455a-a5e3-2c863de18b05") } assertEquals(ErrorCode.NOT_FOUND_ORDER, exception.errorCode) }