100 lines
3.8 KiB
Kotlin

package com.sangdol.validation
import org.hamcrest.CoreMatchers.containsString
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.CsvSource
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.jsonPath
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
@WebMvcTest(controllers = [DemoController::class])
@MockitoBean(types = [DemoService::class])
class DemoControllerTest {
@Autowired
private val mockMvc: MockMvc? = null
@DisplayName("Wrapper 타입인 경우 값이 입력되지 않으면 HttpMessageNotReadableException이 발생한다.")
@ParameterizedTest(name = "{0}")
@CsvSource(
value = [
"@NotNull 필드의 값만 입력되는 경우 ; withAnnotation",
"@NotNull이 아닌 필드의 값만 입력되는 경우 ; withoutAnnotation"
],
delimiter = ';'
)
fun except_wrapper_field(testName: String, field: String) {
val endpoint = "/wrapper"
val value = "message"
val body = "{\"$field\": \"$value\"}"
runException(endpoint, body, HttpStatus.BAD_REQUEST.value(), "HttpMessageNotReadableException")
}
@DisplayName("Primitive 타입인 경우 @NotNull 지정과 무관하게 값이 입력되지 않아도 기본값이 들어간다.")
@ParameterizedTest(name = "{0}")
@CsvSource(
value = [
"@NotNull 필드의 값만 입력되는 경우 ; withAnnotation",
"@NotNull이 아닌 필드의 값만 입력되는 경우 ; withoutAnnotation"
],
delimiter = ';'
)
fun except_primitive_field(testName: String, field: String) {
val endpoint = "/primitive"
val value = 10
val body = "{\"$field\": $value}"
run(endpoint, body, HttpStatus.OK.value())
}
@DisplayName("Primitive 타입인 경우 Bean Validation을 위해서는 @NotNull + nullable 필드 지정이 필요하다.")
@ParameterizedTest(name = "{0}")
@CsvSource(
value = [
"""필드가 없는 경우 ; {"notExistField": 10} ; 400""",
"""필드가 Null인 경우 ; {"value": null} ; 400""",
"""필드의 값이 정상인 경우 ; {"value": 10} ; 200"""
], delimiter = ';'
)
fun primitive_validation_with_nullable_field(testName: String, body: String, expectedStatus: Int) {
val endpoint = "/solution"
if (expectedStatus == HttpStatus.OK.value()) {
run(endpoint, body, expectedStatus)
} else {
runException(endpoint, body, expectedStatus, "MethodArgumentNotValidException")
}
}
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)
)
)
}