입력값을 특정 값으로 지정하는 것의 한계
입력값을 다음과 같이 지정하게 되면, getNameByUserId에 0xffffffff이 입력되었을 때만 "TestUser"이 반환된다.
every { userRepository.getNameByUserId("0xffffffff") } returns "TestUser"
그렇다면 만약 유효한 아이디 일 경우에 "TestUser"을 반환하고, 유효하지 않은 아이디일 경우에는 예외를 반환하는 목 객체는 어떻게 만들 수 있을까? 만약 유효한 아이디가 8자리의 16진수값이라면, 이에 대한 모든 값에 대해 every를 작성하게 되면 수십억줄의 코드를 작성해야 할 수 있다.
이런 경우 만약 입력 값을 특정 범위로 지정할 수 있다면 매우 도움이 될 것이다. 이를 위해 MockK라이브러리는 입력 값을 범위로 지정할 수 있는 방법을 지원한다. 이어서 이 방법에 대해 알아보자.
every를 match와 같이 사용해 입력값을 범위로 지정하기
입력값에 match를 사용하면 특정한 범위의 값들을 입력값으로 지정할 수 있다. 예를 들어 문자가 0x로 시작하고, 총 길이가 10이며, 3번째 자리부터 10번째 자리까지 16진수인 경우의 반환값을 "TestUser"로 설정하기 위해서는 다음과 같이 작성될 수 있다.
every {
userRepository.getNameByUserId(
match {
it.startsWith("0x") &&
it.length == 10 &&
isHexadecimal(it.substring(2))
}
)
}.returns("TestUser")
*물론 아이디가 유효한지 판단하는 것은 객체가 해야 하지만, 여기서는 예시를 위해 이렇게 만들었다.
이런 방식으로 아이디가 유효할 때만 유저의 이름을 반환하도록 만들고 이외의 경우에는 IllegalArgumentException을 발생하도록 만들면, 유효한 아이디를 사용해 유저 이름이 조회되었을 때 UserRepository가 제대로 결과를 반환하도록 만들 수 있다.
class UserProfileFetcherTest {
@Test
fun dummyTest() {
// Given
val userRepository: UserRepository = mockk()
val userProfileFetcher = UserProfileFetcher(
userRepository = userRepository
)
every {
userRepository.getNameByUserId(
match {
it.startsWith("0x") &&
it.length == 10 &&
isHexadecimal(it.substring(2))
}
)
}.returns("TestUser")
every {
userRepository.getNameByUserId(
match {
(
it.startsWith("0x") &&
it.length == 10 &&
isHexadecimal(it.substring(2))
).not()
}
)
}.throws(IllegalArgumentException("UserIdError"))
// When
val result = userProfileFetcher.getUserProfileById("0x12345678")
// Then
assertEquals("TestUser", result.name)
}
private fun isHexadecimal(input: String): Boolean {
val hexRegex = Regex("^[0-9A-Fa-f]+$")
return hexRegex.matches(input)
}
}
테스트를 실행해보면 테스트가 성공하는 것을 확인할 수 있다.
그렇다면 유효하지 않은 아이디로 같은 테스트를 진행했을 때 성공하는지 살펴보자.
class UserProfileFetcherTest {
@Test
fun dummyTest() {
// Given
val userRepository: UserRepository = mockk()
val userProfileFetcher = UserProfileFetcher(
userRepository = userRepository
)
every {
userRepository.getNameByUserId(
match {
it.startsWith("0x") &&
it.length == 10 &&
isHexadecimal(it.substring(2))
}
)
}.returns("TestUser")
every {
userRepository.getNameByUserId(
match {
(
it.startsWith("0x") &&
it.length == 10 &&
isHexadecimal(it.substring(2))
).not()
}
)
}.throws(IllegalArgumentException("UserIdError"))
// When
val result = userProfileFetcher.getUserProfileById("0xzzzzzzzz") // 유효하지 않은 아이디
// Then
assertEquals("TestUser", result.name)
}
private fun isHexadecimal(input: String): Boolean {
val hexRegex = Regex("^[0-9A-Fa-f]+$")
return hexRegex.matches(input)
}
}
그러면 IllegalArgumentException이 발생하며 테스트가 실패하는 것을 볼 수 있다.
정리
every와 match를 함께 사용하면 입력 값을 범위로 설정할 수 있다. 만약 특정한 범위의 입력에 대해서만 특정한 결과값이 나와야 한다면 match를 사용하도록 하자.