Mockito에서 when은 어떤 역할을 하는가?
Mockito의 when은 Test Double 중 Stub를 만들 수 있는 강력한 무기이다. when을 통해 Mock 객체의 메서드를 호출 했을 때 특정한 응답을 주도록 만들 수 있다.
* Stub : Mock 객체에 특정한 입력 시 특정한 출력을 주도록 만드는 것
when 을 사용하기 위한 환경 설정
https://simcode.tistory.com/12 의 LoginRepository, LoginRepositoryResult, LoginUseCase, LoginUseCaseResult 를 모두 가져온다.
when 사용하기
메서드를 실행하면 특정한 응답을 할 수도 있고, 응답이 매번 바뀔 수도 있고, 애러가 발생할 수도 있다. 따라서 when을 사용하는 방법은 다양하다. 이 중 자주 사용되는 3가지 메서드 thenReturn, thenAnswer, doThrow에 대해 알아볼 것이다.
thenReturn 사용해 특정한 응답 주기
thenReturn을 사용하면 특정한 응답을 줄 수 있다. 예를 들어 Mock객체인 loginRepository에서 loginRepository.login(userName = "success", password = "success") 를 호출 했을 때 LoginRepositoryResult.Success("test_token")를 return 하도록 만들 수 있다.
이를 thenReturn을 사용해 만들면 코드는 다음과 같아진다.
val repositorySuccessResult = LoginRepositoryResult.Success("test_token")
Mockito.`when`(loginRepository.login(userName = "success", password = "success"))
.thenReturn(repositorySuccessResult)
그러면 이제 loginRepository를 사용하는 loginUseCase에서 login을 호출했을 때 "test_token"이 return 될 것을 기대할 수 있어진다. 따라서 아래와 같이 테스트를 작성할 수 있다.
@Test
fun testLoginThenReturn() {
val repositorySuccessResult = LoginRepositoryResult.Success("test_token")
Mockito.`when`(loginRepository.login(userName = "success", password = "success"))
.thenReturn(repositorySuccessResult)
val result = loginUseCase.logIn(userName = "success", password = "success")
Assert.assertEquals(LoginUseCaseResult.Success("test_token"), result)
}
thenAnswer 사용해 응답을 매번 바꾸기
thenReturn은 특정한 입력에 대해 한가지 응답만이 가능하다. 따라서 여러번 호출해도 매번 응답이 똑같다. 하지만, 하나의 입력에 대해 매번 바뀌는 응답을 받고 싶을 수 있다. 이때 thenAnswer을 사용한다.
loginRepository.login(userName = "test", password = "test") 를 호출 했을 때 매번 응답이 LoginRepositoryResult.Success("cba") , LoginRepositoryResult.Success("abc") 사이에서 바뀌도록 하고 싶다면 다음과 같이 코드를 작성하면 된다.
@Test
fun testLoginThenAnswer() {
Mockito.`when`(loginRepository.login("test", "test"))
.thenAnswer(object : Answer<LoginRepositoryResult> {
var token = "abc"
override fun answer(invocation: InvocationOnMock?): LoginRepositoryResult {
token = token.reversed()
return LoginRepositoryResult.Success(token)
}
})
그러면 다음과 같이 결과값이 매번 바뀌는 것을 확인할 수 있다.
val result1 = loginUseCase.logIn(userName = "test", password = "test")
println(result1) // "cba"
val result2 = loginUseCase.logIn(userName = "test", password = "test")
println(result2) // "abc"
전체 코드는 다음과 같다.
@Test
fun testLoginThenAnswer() {
Mockito.`when`(loginRepository.login("test", "test"))
.thenAnswer(object : Answer<LoginRepositoryResult> {
var token = "abc"
override fun answer(invocation: InvocationOnMock?): LoginRepositoryResult {
token = token.reversed()
return LoginRepositoryResult.Success(token)
}
})
val result1 = loginUseCase.logIn(userName = "test", password = "test")
println(result1) // "cba"
val result2 = loginUseCase.logIn(userName = "test", password = "test")
println(result2) // "abc"
}
doThrow 사용해 애러 발생시키기
doThrow를 사용하면 메서드가 호출되었을 때 애러를 발생시킬 수 있다.
예를 들어 loginRepository.login("error", "error") 가 호출되면 IllegalStateException을 발생시키고 싶다면 다음과 같이 코드를 작성하면 된다.
Mockito.`when`(loginRepository.login("error", "error"))
.doThrow(IllegalStateException())
when을 뒤로 보낼 수도 있다.
Mockito.doThrow(IllegalStateException::class.java)
.`when`(loginRepository).login("error", "error")
전체 코드는 다음과 같다.
@Test
fun testLoginDoThrow1() {
Mockito.`when`(loginRepository.login("error", "error"))
.doThrow(IllegalStateException())
Assert.assertThrows(IllegalStateException::class.java) { loginUseCase.logIn("error", "error") };
}
@Test
fun testLoginDoThrow2() {
Mockito.doThrow(IllegalStateException::class.java)
.`when`(loginRepository).login("error", "error")
Assert.assertThrows(IllegalStateException::class.java) { loginUseCase.logIn("error", "error") };
}
when 정리하기
Mock 객체가 테스트 대상 객체에 영향을 주지 않도록 적절한 Stub을 만드는 것은 테스트의 완성도를 위해 매우 중요하다. 이번 글에서는 when을 사용해 다양한 Stub을 만드는 방법 알아보았다. 적절한 Stub을 만들어 테스트 완성도를 높이도록 하자.
'Unit Testing' 카테고리의 다른 글
Kotlin에서 Mockito ArgumentCaptor 사용시 java.lang.NullPointerException: argumentCaptor.capture() must not be null 나오는 현상 해결 방법 (0) | 2022.12.22 |
---|---|
[Mockito] ArgumentCaptor 사용해 객체의 interaction 기록하기 (0) | 2022.12.21 |
[Unit Testing] Mockito 사용해 Test Double 만들기 (0) | 2022.12.19 |
Test Double이란 무엇인가? Test Double의 종류, 사용법 알아보기 (0) | 2022.12.18 |
Unit Testing에서 Test Double이 필요한 이유는 무엇일까? (0) | 2022.12.17 |