반응형
Validation 시리즈
1. Spring Bean Validation - Basic
2. Spring Bean Validation - Custom Annotation
3. Spring Bean Validation - Test Code

앞서 Validation 체크를 하기 위해 @WebMvcTest를 사용했지만 너무 준비할것이 많고, JSON을 문자열로 직접 작성해야하기 때문에 번거롭기까지 하다. 거기다가 Spring Container를 사용하기 때문에 빠른테스트가 불가능하다.

 

앞서 만든 Member 클래스를 유효성 검사하는 테스트 코드를 만들어보자

data class Member(
    @field:NotBlank(message = "이름을 입력하세요")
    val name : String,

    @field:NotBlank(message = "이메일을 확인하세요")
    @field:Email(message = "이메일을 확인하세요")
    val email : String,

    @field:Range(min = 18, max = 36, message = "나이를 확인하세요")
    val age : Int,

    @field:Max(value = 5, message="5를 넘을 수 없습니다")
    val count : Int
)

테스트코드

class MemberValidationTest {

    lateinit var validator : Validator

    @BeforeEach
    internal fun setUp() {
        validator = Validation.buildDefaultValidatorFactory().validator;
    }

    @Test
    fun ageValidation(){
        val validate : Set<ConstraintViolation<Member>> =
            validator.validate(Member("라이언", "email@email.com", 10, 0))
        assertTrue(validate.size == 1)
    }
}

너무나 간단하게 테스트코드를 작성했다.

validator를 가져와서 validate를 하여 나온 결과값이 1이면 테스트가 통과한다. 하지만 한가지 문제가 있는데 현재 발생한 유효성검사가 정말 age에 관련된 테스트일까? 기존 Member클래스의 유효성 검사가 변경되어 age가 문제가 아닌 다른곳에서 유효성이 터졌다면 그 결과도 1이 된다.

더 정확하게 테스트하기 위해 다음과 같이 추가했다

@Test
fun ageValidation(){
    val validate : Set<ConstraintViolation<Member>> =
        validator.validate(Member("라이언", "email@email.com", 10, 0))
    assertTrue(validate.size == 1)
    with(validate.first()){
        assertEquals("age", this.propertyPath.toString())
    }
}

size를 체크하여 1개의 유효성 체크가 된것을 확인 했고, 그 첫번째 값을 가져와 age 프로퍼티에서 유효성 체크가 된것을 확인할 수 있다. 좀더 명확하게 테스트를 할 수 있게 되었다

여러케이스에 대한 테스트

여러가지 케이스에 대한 유효성 검사를 해보자.

@Test
fun validations(){
    val member1 = Member("", "email@email.com", 20, 0)
    val validate1 = validator.validate(member1)
    assertTrue(validate1.size == 1)
    with(validate1.first()){
        assertEquals("name", this.propertyPath.toString())
    }

    val member2 = Member("라이언1", "email", 20, 0)
    val validate2 = validator.validate(member2)
    assertTrue(validate2.size == 1)
    with(validate2.first()){
        assertEquals("email", this.propertyPath.toString())
    }

    val member3 = Member("라이언1", "email@email.com", 20, 9)
    val validate3 = validator.validate(member3)
    assertTrue(validate3.size == 1)
    with(validate3.first()){
        assertEquals("count", this.propertyPath.toString())
    }
}

각 항목에 대해서 테스트 케이스를 작성해 보았다. 이렇게 여러가지 테스트케이스를 하여 해당 유효성검사는 이상 없는지 확인할 수 있다

번외 - ParameterizedTest

위의 테스트 코드는 복합적인 유효성 체크에 대한 검사를 하지 않았다. 만약 복합적인 Member 유효성 체크에 대해서 코드로 작성한다면 코드량이 어마어마해질것이다. 아마 쓰다가 지쳐 테스트를 포기할지도 모르겠다. 여러 케이스에 대해 파라미터로 넘겨서 확인 할 수 있도록 해보자

@ParameterizedTest
@MethodSource("testMembers")
fun validationsWithParameterized(case : Pair<Member, Set<String>>){
    val validates = validator.validate(case.first)
    assertTrue(validates.size == case.second.size)
    validates.forEach {
        assertTrue(case.second.contains(it.propertyPath.toString()))
    }
}


companion object{
    @JvmStatic
    fun testMembers() : Stream<Pair<Member, Set<String>>> =
        Stream.of(
            Member("라이언1", "email@email.com", 10, 0) to setOf("age"),
            Member("", "email@email.com", 10, 0) to setOf("name", "age"),
            Member("", "", 10, 9) to setOf("name", "email", "age", "count"),
        )
}

@ParameterizedTest 어노테이션은 테스트메소드에 파라미터를 넘겨서 사용할 수 있게 한다. @MethodSource는 @ValueSource, @EnumSource같이 값이나 Enum이 아닌 오브젝트를 파라미터로 넘길때 사용된다. 

 

@MethodSource는 다음과 같은 조건을 맞춰야한다

  • static 메소드여야한다 (@TestInstance가 PER_CLASS이면 일반 메소드여도 괜찮다)
  • 파라미터가 없어야 한다
  • Stream으로 리턴해야한다

 

Kotlin에서는 static이 따로 없기 때문에 companion object로 만들어주고 @JvmStatic을 사용하여 Java의 static처럼 사용하게 한다. 그리고 Stream으로 각 테스트 케이스에 해당하는 Member를 만들고 유효성 체크에 필요한 필드이름을 정의하고 Set으로 묶은뒤 파라미터로 전달한다.

마지막으로 validate를 처리하여 유효성 체크 필드에 포함되는지 확인하면 테스트는 끝나게 된다. 나중에 testMembers에 여러케이스를 추가하기만 하면 된다.

반응형

'개발 > Kotlin' 카테고리의 다른 글

Gradle - dependency-management Plugin  (0) 2022.06.19
QueryDSL 설정 - Kotlin  (0) 2022.06.19
Kotlin Basic - 함수와 변수  (0) 2022.06.18
Spring Bean Validation - Custom Annotation  (0) 2022.04.17
Spring Bean Validation - Basic  (0) 2022.04.12

+ Recent posts