generated from pricelees/issue-pr-template
test: 기존 Junit 테스트와 동일한 Kotest 기반 테스트 추가
This commit is contained in:
parent
3ba9c17169
commit
9cfbbf1902
@ -12,7 +12,10 @@
|
|||||||
git clone https://gitea.pricelees.me/pricelees/kopring-validation.git
|
git clone https://gitea.pricelees.me/pricelees/kopring-validation.git
|
||||||
|
|
||||||
// 테스트 실행 후 콘솔 출력 결과 확인
|
// 테스트 실행 후 콘솔 출력 결과 확인
|
||||||
src.test/kotlin/com/sangdol/validation/ValidationTest.kt
|
src/test/kotlin/com/sangdol/validation/DemoControllerTest
|
||||||
|
|
||||||
|
// Kotest 버전
|
||||||
|
src/test/kotlin/com/sangdol/validation/DemoControllerKTest
|
||||||
```
|
```
|
||||||
`src/main/kotlin/com/sangdol/validation/DemoDTO.kt` 를 Decompile 하여 상황에 따라 어노테이션이 어떻게 붙는지 확인할 수 있습니다.
|
`src/main/kotlin/com/sangdol/validation/DemoDTO.kt` 를 Decompile 하여 상황에 따라 어노테이션이 어떻게 붙는지 확인할 수 있습니다.
|
||||||
- 같은 @NotNull 이라도 jakarta / jetbrains 패키지인지에 따라 처리되는 방법이 다르며, 자세한 내용은 위 글에서 확인할 수 있습니다.
|
- 같은 @NotNull 이라도 jakarta / jetbrains 패키지인지에 따라 처리되는 방법이 다르며, 자세한 내용은 위 글에서 확인할 수 있습니다.
|
||||||
@ -31,6 +31,9 @@ dependencies {
|
|||||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||||
implementation("io.github.oshai:kotlin-logging-jvm:7.0.3")
|
implementation("io.github.oshai:kotlin-logging-jvm:7.0.3")
|
||||||
|
|
||||||
|
testImplementation("io.mockk:mockk:1.14.4")
|
||||||
|
testImplementation("io.kotest:kotest-runner-junit5:5.9.1")
|
||||||
|
testImplementation("io.kotest.extensions:kotest-extensions-spring:1.3.0")
|
||||||
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
||||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,90 @@
|
|||||||
|
package com.sangdol.validation
|
||||||
|
|
||||||
|
import io.kotest.core.annotation.DisplayName
|
||||||
|
import io.kotest.core.spec.style.BehaviorSpec
|
||||||
|
import org.hamcrest.CoreMatchers.containsString
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
||||||
|
import org.springframework.http.HttpStatus
|
||||||
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.test.context.bean.override.mockito.MockitoBean
|
||||||
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
|
import org.springframework.test.web.servlet.ResultActions
|
||||||
|
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
|
||||||
|
import org.springframework.test.web.servlet.result.MockMvcResultHandlers.print
|
||||||
|
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
@WebMvcTest(controllers = [DemoController::class])
|
||||||
|
@DisplayName("타입별 Bean Validation 테스트")
|
||||||
|
class DemoControllerKTest(
|
||||||
|
@Autowired private val mockMvc: MockMvc,
|
||||||
|
@MockitoBean private val demoService: DemoService
|
||||||
|
) : BehaviorSpec() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
Given("Wrapper 타입에서는") {
|
||||||
|
val endpoint = "/wrapper"
|
||||||
|
val value = "value"
|
||||||
|
|
||||||
|
When("값이 입력되지 않으면") {
|
||||||
|
val expectedStatus = HttpStatus.BAD_REQUEST.value()
|
||||||
|
val expectedError = "HttpMessageNotReadableException"
|
||||||
|
|
||||||
|
Then("HttpMessageNotReadableException이 발생한다.") {
|
||||||
|
val body = "{\"withAnnotation\": \"$value\"}"
|
||||||
|
runException(endpoint, body, expectedStatus, expectedError)
|
||||||
|
}
|
||||||
|
|
||||||
|
Then("@NotNull이 적용되지 않고 HttpMessageNotReadableException이 발생한다.") {
|
||||||
|
val body = "{\"withoutAnnotation\": \"$value\"}"
|
||||||
|
runException(endpoint, body, expectedStatus, expectedError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Given("Primitive 타입에서는") {
|
||||||
|
val endpoint = "/primitive"
|
||||||
|
val value = Random.nextInt()
|
||||||
|
|
||||||
|
When("값을 입력하지 않아도") {
|
||||||
|
val expectedStatus = HttpStatus.OK.value()
|
||||||
|
|
||||||
|
Then("@NotNull과 무관하게 기본값이 들어간다.") {
|
||||||
|
run(endpoint, "{\"withoutAnnotation\": \"$value\"}", expectedStatus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Given("Primitive 타입에서 @NotNull + Nullable 으로 선언한 경우에는") {
|
||||||
|
val endpoint = "/solution"
|
||||||
|
|
||||||
|
When("값이 입력되지 않으면") {
|
||||||
|
val body = "{\"notExistField\": 10}"
|
||||||
|
val expectedStatus = HttpStatus.BAD_REQUEST.value()
|
||||||
|
val expectedError = "MethodArgumentNotValidException"
|
||||||
|
|
||||||
|
Then("@NotNull Bean Validation이 적용된다.") {
|
||||||
|
runException(endpoint, body, expectedStatus, expectedError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun run(endpoint: String, body: String, expectedStatus: Int): ResultActions =
|
||||||
|
mockMvc.perform(
|
||||||
|
post(endpoint)
|
||||||
|
.contentType(MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
.content(body)
|
||||||
|
).andExpect(status().`is`(expectedStatus))
|
||||||
|
.andDo(print())
|
||||||
|
|
||||||
|
private fun runException(
|
||||||
|
endpoint: String,
|
||||||
|
body: String,
|
||||||
|
expectedStatus: Int,
|
||||||
|
expectedExceptionType: String
|
||||||
|
): ResultActions =
|
||||||
|
run(endpoint, body, expectedStatus)
|
||||||
|
.andExpect(jsonPath("$.type", containsString(expectedExceptionType)))
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user