generated from pricelees/issue-pr-template
[#50] Tosspay API Mocking 서버 구현 #51
@ -0,0 +1,188 @@
|
||||
package com.sangdol.tosspaymock
|
||||
|
||||
import com.sangdol.common.persistence.IDGenerator
|
||||
import com.sangdol.tosspaymock.exception.code.TosspayCancelErrorCode
|
||||
import com.sangdol.tosspaymock.exception.code.TosspayConfirmErrorCode
|
||||
import com.sangdol.tosspaymock.infrastructure.persistence.OrderAmountEntity
|
||||
import com.sangdol.tosspaymock.infrastructure.persistence.OrderAmountRepository
|
||||
import com.sangdol.tosspaymock.web.dto.PaymentCancelRequest
|
||||
import com.sangdol.tosspaymock.web.dto.PaymentConfirmRequest
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.nulls.shouldNotBeNull
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.restassured.RestAssured
|
||||
import io.restassured.module.kotlin.extensions.Extract
|
||||
import io.restassured.module.kotlin.extensions.Given
|
||||
import io.restassured.module.kotlin.extensions.Then
|
||||
import io.restassured.module.kotlin.extensions.When
|
||||
import org.hamcrest.CoreMatchers
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.test.web.server.LocalServerPort
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.MediaType
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
class TosspayApiTest(
|
||||
@LocalServerPort private val port: Int,
|
||||
private val orderAmountRepository: OrderAmountRepository,
|
||||
private val idGenerator: IDGenerator
|
||||
) : FunSpec({
|
||||
|
||||
beforeSpec {
|
||||
RestAssured.port = port
|
||||
}
|
||||
|
||||
afterTest {
|
||||
orderAmountRepository.deleteAll()
|
||||
}
|
||||
|
||||
val authorizationKey = "dGVzdF9nc2tfZG9jc19PYVB6OEw1S2RtUVhrelJ6M3k0N0JNdzY6"
|
||||
|
||||
val paymentConfirmRequest = PaymentConfirmRequest(
|
||||
paymentKey = "5EnNZRJGvaBX7zk2yd8ydw26XvwXkLrx9POLqKQjmAw4b0e1",
|
||||
orderId = "MC4wODU4ODQwMzg4NDk0",
|
||||
amount = 100_000,
|
||||
)
|
||||
|
||||
val paymentCancelRequest = PaymentCancelRequest(
|
||||
cancelAmount = paymentConfirmRequest.amount,
|
||||
cancelReason = "그냥.."
|
||||
)
|
||||
|
||||
context("결제 승인") {
|
||||
val paymentConfirmRequest = PaymentConfirmRequest(
|
||||
paymentKey = "5EnNZRJGvaBX7zk2yd8ydw26XvwXkLrx9POLqKQjmAw4b0e1",
|
||||
orderId = "MC4wODU4ODQwMzg4NDk0",
|
||||
amount = 100_000,
|
||||
)
|
||||
|
||||
test("Basic Authorization 헤더가 없으면 실패한다.") {
|
||||
Given {
|
||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||
body(paymentConfirmRequest)
|
||||
} When {
|
||||
post("/v1/payments/confirm")
|
||||
} Then {
|
||||
statusCode(HttpStatus.BAD_REQUEST.value())
|
||||
body("code", CoreMatchers.equalTo(TosspayConfirmErrorCode.INVALID_API_KEY.name))
|
||||
}
|
||||
}
|
||||
|
||||
test("Basic Authorization 헤더가 Base64 형식이 아니면 실패한다.") {
|
||||
Given {
|
||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||
header("Authorization", "Basic hello-world")
|
||||
body(paymentConfirmRequest)
|
||||
} When {
|
||||
post("/v1/payments/confirm")
|
||||
} Then {
|
||||
statusCode(HttpStatus.UNAUTHORIZED.value())
|
||||
body("code", CoreMatchers.equalTo(TosspayConfirmErrorCode.UNAUTHORIZED_KEY.name))
|
||||
}
|
||||
}
|
||||
|
||||
test("임의의 결제 정보를 반환하며, 금액은 별도로 저장한다.") {
|
||||
val paymentKey = Given {
|
||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||
header("Authorization", "Basic $authorizationKey")
|
||||
body(paymentConfirmRequest)
|
||||
} When {
|
||||
post("/v1/payments/confirm")
|
||||
} Then {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
} Extract {
|
||||
path<String>("paymentKey")
|
||||
}
|
||||
|
||||
paymentKey shouldBe paymentConfirmRequest.paymentKey
|
||||
orderAmountRepository.findByPaymentKey(paymentKey).shouldNotBeNull()
|
||||
}
|
||||
}
|
||||
|
||||
context("결제 취소") {
|
||||
test("Basic Authorization 헤더가 없으면 실패한다.") {
|
||||
Given {
|
||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||
body(paymentCancelRequest)
|
||||
} When {
|
||||
post("/v1/payments/${paymentConfirmRequest.paymentKey}/cancel")
|
||||
} Then {
|
||||
statusCode(HttpStatus.BAD_REQUEST.value())
|
||||
body("code", CoreMatchers.equalTo(TosspayConfirmErrorCode.INVALID_API_KEY.name))
|
||||
}
|
||||
}
|
||||
|
||||
test("Basic Authorization 헤더가 Base64 형식이 아니면 실패한다.") {
|
||||
Given {
|
||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||
header("Authorization", "Basic hello-world")
|
||||
body(paymentCancelRequest)
|
||||
} When {
|
||||
post("/v1/payments/${paymentConfirmRequest.paymentKey}/cancel")
|
||||
} Then {
|
||||
statusCode(HttpStatus.UNAUTHORIZED.value())
|
||||
body("code", CoreMatchers.equalTo(TosspayConfirmErrorCode.UNAUTHORIZED_KEY.name))
|
||||
}
|
||||
}
|
||||
|
||||
context("정상 응답") {
|
||||
lateinit var orderAmount: OrderAmountEntity
|
||||
|
||||
beforeTest {
|
||||
orderAmount = OrderAmountEntity(
|
||||
id = idGenerator.create(),
|
||||
paymentKey = paymentConfirmRequest.paymentKey,
|
||||
approvedAmount = (paymentConfirmRequest.amount - 1000),
|
||||
easypayDiscountAmount = 1000,
|
||||
cardDiscountAmount = 0,
|
||||
transferDiscountAmount = 0
|
||||
).also {
|
||||
orderAmountRepository.saveAndFlush(it)
|
||||
}
|
||||
}
|
||||
|
||||
test("요청에 cancelAmount를 포함하지 않으면 전체 금액을 취소한다.") {
|
||||
Given {
|
||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||
header("Authorization", "Basic $authorizationKey")
|
||||
body(PaymentCancelRequest(cancelReason = "그냥!"))
|
||||
} When {
|
||||
post("/v1/payments/${paymentConfirmRequest.paymentKey}/cancel")
|
||||
} Then {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("paymentKey", CoreMatchers.equalTo(paymentConfirmRequest.paymentKey))
|
||||
body("cancels.easyPayDiscountAmount", CoreMatchers.equalTo(orderAmount.easypayDiscountAmount))
|
||||
body("cancels.cancelAmount", CoreMatchers.equalTo(orderAmount.totalAmount()))
|
||||
}
|
||||
}
|
||||
|
||||
test("이전 결제 정보의 할인 금액을 가져온 뒤 반환한다.") {
|
||||
Given {
|
||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||
header("Authorization", "Basic $authorizationKey")
|
||||
body(paymentCancelRequest)
|
||||
} When {
|
||||
post("/v1/payments/${paymentConfirmRequest.paymentKey}/cancel")
|
||||
} Then {
|
||||
statusCode(HttpStatus.OK.value())
|
||||
body("paymentKey", CoreMatchers.equalTo(paymentConfirmRequest.paymentKey))
|
||||
body("cancels.easyPayDiscountAmount", CoreMatchers.equalTo(orderAmount.easypayDiscountAmount))
|
||||
body("cancels.cancelAmount", CoreMatchers.equalTo(paymentCancelRequest.cancelAmount))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test("이전 결제 정보가 없으면 실패한다.") {
|
||||
Given {
|
||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||
header("Authorization", "Basic $authorizationKey")
|
||||
body(paymentCancelRequest)
|
||||
} When {
|
||||
post("/v1/payments/notExistPaymentKey/cancel")
|
||||
} Then {
|
||||
statusCode(HttpStatus.NOT_FOUND.value())
|
||||
body("code", CoreMatchers.equalTo(TosspayCancelErrorCode.NOT_FOUND_PAYMENT.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user