MockK란 무엇인가?
MockK는 코틀린에서 테스트 시 목(Mock) 객체를 생성하는 것을 돕는 라이브러리이다. 기존에 목 객체를 만들기 위해서는 인터페이스를 목 클래스로 직접 구현을 해야 했는데, MockK를 사용하면 간단하게 목 객체를 생성할 수 있다.
Gradle에 MockK 의존성 추가하기
Gradle에 MockK에 대한 의존성은 다음과 같이 추가해주면 된다.
dependencies {
...
// MockK 라이브러리
testImplementation("io.mockk:mockk:1.13.8")
}
MockK의 사용
MockK를 사용하는 것은 매우 간단하다. 예를 들어 다음과 같은 UserProfileFetcher이 있다고 해보자.
class UserProfileFetcher(
private val userRepository: UserRepository,
private val contactRepository: ContactRepository
) {
fun getUserProfileById(id: String): UserProfile {
return UserProfile(
id = id,
name = userRepository.getNameByUserId(id),
phoneNumber = contactRepository.getPhoneNumberByUserId(id)
)
}
}
UserProfileFetcher은 UserRepository와 ContactRepository에 대한 의존성을 가지므로, UserProfileFetcher을 테스트 하기 위해서는 이 두 객체를 주입해주어야 한다. MockK를 사용하지 않고 이 두 객체를 주입하기 위해서는 이 두 객체를 모방하는 Test Doubles를 직접 만들어 주입해주어야 하지만, MockK를 사용하면 다음과 같이 매우 간단하게 주입할 수 있다.
class UserProfileFetcherTest {
@Test
fun testInteraction() {
// Given
val userRepository : UserRepository = mockk()
val contactRepository : ContactRepository = mockk()
val userProfileFetcher = UserProfileFetcher(
userRepository = userRepository,
contactRepository = contactRepository
)
...
}
}
목 객체를 만들고 싶은 객체에 대해 mockk 함수를 사용하는 것 만으로 목 객체를 만들 수 있다. 물론 이렇게 만든 목 객체는 아무런 동작을 하지 못한다. 만들어진 목 객체가 특정한 동작을 하도록 만들고 싶으면 별도의 동작을 설정해야 한다. 예를 들어 UserRepository의 getUserNameById을 호출 했을 때 언제나 'TestUser'을 반환하도록 만들고, ContactRepository의 getPhoneNumberByUserId을 호출 했을 때 언제나 '010-xxxx-xxxx'를 반환하도록 만들고 싶으면 다음과 같이 쓰면 된다.
class UserProfileFetcherTest {
@Test
fun testInteraction() {
// Given
val userRepository : UserRepository = mockk()
val contactRepository : ContactRepository = mockk()
val userProfileFetcher = UserProfileFetcher(
userRepository = userRepository,
contactRepository = contactRepository
)
every { userRepository.getNameByUserId(any()) }.returns("TestUser")
every { contactRepository.getPhoneNumberByUserId(any()) }.returns("010-xxxx-xxxx")
// When
val userProfile = userProfileFetcher.getUserProfileById("test")
// Then
assertEquals("TestUser", userProfile.name)
assertEquals("010-xxxx-xxxx", userProfile.phoneNumber)
}
}
이 테스트에서는 UserProfileFetcher을 사용해 유저 프로필을 가져온 후 이름과, 휴대전화번호가 예상된대로 반환되는지 확인하는 테스트를 진행한다. UserProfileFetcher는 유저의 이름을 UserRepository로부터 가져오고 휴대전화번호를 ContactRepository로부터 가져오므로, 코드를 실행해보면 테스트가 통과되는 것을 볼 수 있다.