generated from pricelees/issue-pr-template
<!-- 제목 양식 --> <!-- [이슈번호] 작업 요약 (예시: [#10] Gitea 템플릿 생성) --> ## 📝 관련 이슈 및 PR **PR과 관련된 이슈 번호** - #11 ## ✨ 작업 내용 <!-- 어떤 작업을 했는지 알려주세요! --> payment 패키지 내 코드, 테스트를 코틀린으로 전환했고 일부 로직은 개선하였음. 전체적으로 구조를 개선하려고 했으나, 얽혀있는 예약 관련 로직이 많아 전체 코드의 코틀린 전환이 끝난 이후 개선할 예정 ## 🧪 테스트 <!-- 어떤 테스트를 생각했고 진행했는지 알려주세요! --> 1. \@DataJpaTest를 이용하는 Repository 테스트를 추가 2. Service는 mocking 방식으로 수정하였고, 테스트가 불필요하다고 여겨지는 단순 로직(변환 또는 Repository만 사용하는 경우)은 제외하였음. (8577b68496) - 전체 로직이 테스트되어있는 기존의 테스트는 유지하였고, 전체 코틀린 전환이 마무리 된 후 제거 예정 ## 📚 참고 자료 및 기타 <!-- 참고한 자료, 또는 논의할 사항이 있다면 알려주세요! --> Reviewed-on: #12 Co-authored-by: pricelees <priceelees@gmail.com> Co-committed-by: pricelees <priceelees@gmail.com>
140 lines
5.6 KiB
Kotlin
140 lines
5.6 KiB
Kotlin
package roomescape.payment.infrastructure.client
|
|
|
|
import io.kotest.assertions.assertSoftly
|
|
import io.kotest.assertions.throwables.shouldThrow
|
|
import io.kotest.core.spec.style.FunSpec
|
|
import io.kotest.matchers.shouldBe
|
|
import org.springframework.beans.factory.annotation.Autowired
|
|
import org.springframework.boot.test.autoconfigure.web.client.RestClientTest
|
|
import org.springframework.http.HttpMethod
|
|
import org.springframework.http.HttpStatus
|
|
import org.springframework.http.MediaType
|
|
import org.springframework.test.web.client.MockRestServiceServer
|
|
import org.springframework.test.web.client.ResponseActions
|
|
import org.springframework.test.web.client.match.MockRestRequestMatchers.*
|
|
import org.springframework.test.web.client.response.MockRestResponseCreators.withStatus
|
|
import org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess
|
|
import roomescape.common.exception.ErrorType
|
|
import roomescape.common.exception.RoomescapeException
|
|
import roomescape.payment.SampleTossPaymentConst
|
|
import roomescape.payment.web.PaymentApprove
|
|
import roomescape.payment.web.PaymentCancel
|
|
|
|
@RestClientTest(TossPaymentClient::class)
|
|
class TossPaymentClientTest(
|
|
@Autowired val client: TossPaymentClient,
|
|
@Autowired val mockServer: MockRestServiceServer
|
|
) : FunSpec() {
|
|
|
|
init {
|
|
context("결제 승인 요청") {
|
|
fun commonAction(): ResponseActions = mockServer.expect {
|
|
requestTo("/v1/payments/confirm")
|
|
}.andExpect {
|
|
method(HttpMethod.POST)
|
|
}.andExpect {
|
|
content().contentType(MediaType.APPLICATION_JSON)
|
|
}.andExpect {
|
|
content().json(SampleTossPaymentConst.paymentRequestJson)
|
|
}
|
|
|
|
test("성공 응답") {
|
|
commonAction().andRespond {
|
|
withSuccess()
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.body(SampleTossPaymentConst.confirmJson)
|
|
.createResponse(it)
|
|
}
|
|
|
|
// when
|
|
val paymentRequest = SampleTossPaymentConst.paymentRequest
|
|
val paymentResponse: PaymentApprove.Response = client.confirmPayment(paymentRequest)
|
|
|
|
assertSoftly(paymentResponse) {
|
|
this.paymentKey shouldBe paymentRequest.paymentKey
|
|
this.orderId shouldBe paymentRequest.orderId
|
|
this.totalAmount shouldBe paymentRequest.amount
|
|
}
|
|
}
|
|
|
|
test("400 에러 발생") {
|
|
commonAction().andRespond {
|
|
withStatus(HttpStatus.BAD_REQUEST)
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.body(SampleTossPaymentConst.tossPaymentErrorJson)
|
|
.createResponse(it)
|
|
}
|
|
|
|
// when
|
|
val paymentRequest = SampleTossPaymentConst.paymentRequest
|
|
|
|
// then
|
|
val exception = shouldThrow<RoomescapeException> {
|
|
client.confirmPayment(paymentRequest)
|
|
}
|
|
|
|
assertSoftly(exception) {
|
|
this.errorType shouldBe ErrorType.PAYMENT_ERROR
|
|
this.invalidValue shouldBe "[ErrorCode = ERROR_CODE, ErrorMessage = Error message]"
|
|
this.httpStatus shouldBe HttpStatus.BAD_REQUEST
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
context("결제 취소 요청") {
|
|
fun commonAction(): ResponseActions = mockServer.expect {
|
|
requestTo("/v1/payments/${SampleTossPaymentConst.paymentKey}/cancel")
|
|
}.andExpect {
|
|
method(HttpMethod.POST)
|
|
}.andExpect {
|
|
content().contentType(MediaType.APPLICATION_JSON)
|
|
}.andExpect {
|
|
content().json(SampleTossPaymentConst.cancelRequestJson)
|
|
}
|
|
|
|
test("성공 응답") {
|
|
commonAction().andRespond {
|
|
withSuccess()
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.body(SampleTossPaymentConst.cancelJson)
|
|
.createResponse(it)
|
|
}
|
|
|
|
// when
|
|
val cancelRequest: PaymentCancel.Request = SampleTossPaymentConst.cancelRequest
|
|
val cancelResponse: PaymentCancel.Response = client.cancelPayment(cancelRequest)
|
|
|
|
assertSoftly(cancelResponse) {
|
|
this.cancelStatus shouldBe "DONE"
|
|
this.cancelReason shouldBe cancelRequest.cancelReason
|
|
this.cancelAmount shouldBe cancelRequest.amount
|
|
}
|
|
}
|
|
|
|
test("500 에러 발생") {
|
|
commonAction().andRespond {
|
|
withStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.body(SampleTossPaymentConst.tossPaymentErrorJson)
|
|
.createResponse(it)
|
|
}
|
|
|
|
// when
|
|
val cancelRequest: PaymentCancel.Request = SampleTossPaymentConst.cancelRequest
|
|
|
|
// then
|
|
val exception = shouldThrow<RoomescapeException> {
|
|
client.cancelPayment(cancelRequest)
|
|
}
|
|
|
|
assertSoftly(exception) {
|
|
this.errorType shouldBe ErrorType.PAYMENT_SERVER_ERROR
|
|
this.invalidValue shouldBe "[ErrorCode = ERROR_CODE, ErrorMessage = Error message]"
|
|
this.httpStatus shouldBe HttpStatus.INTERNAL_SERVER_ERROR
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|