Dummy란 무엇인가?
Test Doubles에서 Dummy란 어떤 함수를 호출하든 응답값으로 빈 값을 주는 객체를 뜻한다. 이러한 Dummy는 반환값이 필요없는 객체의 반환값을 설정하기 위해 사용한다. 하지만, 순수한 의미의 Dummy는 응답값이 설정되는 순간부터는 Stub이 되기 때문에 사용처가 한정된다.
테스트를 위한 환경 설정
이 글에서는 ManyGetRepository를 주입 받는 ManyGetUseCase를 테스트 한다.
class ManyGetUseCase(
private val manyGetRepository: ManyGetRepository
) {
fun callGet(int: Int): Int =
when (int) {
0 -> manyGetRepository.getA()
1 -> manyGetRepository.getB()
2 -> manyGetRepository.getC()
else -> {
-1
}
}
}
interface ManyGetRepository {
fun getA(): Int
fun getB(): Int
fun getC(): Int
fun getD(): Int
fun getE(): Int
}
relaxed 사용해 목 객체를 기본적으로 Dummy로 만들기
MockK는 목 객체를 기본적으로 Dummy로 만들지만, 응답값을 별도로 추가로 설정할 수 있도록 함으로써 복잡한 객체에 대한 테스트를 쉽게 만드는 방법을 제공한다. 복잡한 객체는 일부 함수에 대한 응답만을 모방하는 방법으로 테스트를 진행하는데, 이를 위해서 여러 의존성 있는 함수들의 반환값을 설정하기는 쉽지 않기 때문에 이런 경우 복잡한 객체를 기본적으로 Dummy로 만든 후 테스트를 진행한다.
예를 들어 위의 ManyGetUseCase를 테스트하기 위해서는 ManyGetRepository에 대한 응답값을 설정해야 하는데, 이 때 getD와 getE는 사용되지 않기 때문에 응답값을 별도로 설정할 필요가 없다. 이런 경우 다음과 같이 relaxed = true로 설정하고, 관심있는 메서드에 대해서만 반환값을 설정할 수 있다.
class ManyGetUseCaseTest {
@Test
fun `test callGet with relaxed mock`() {
// Mockk 모의 객체 생성 (relaxed 모드)
val mockRepository = mockk<ManyGetRepository>(relaxed = true)
// Mock Repository의 메서드 동작 설정
every { mockRepository.getA() } returns 42
every { mockRepository.getB() } returns 24
every { mockRepository.getC() } returns 18
// 테스트 대상 객체 생성
val useCase = ManyGetUseCase(mockRepository)
// 테스트 케이스
val resultA = useCase.callGet(0)
val resultB = useCase.callGet(1)
val resultC = useCase.callGet(2)
// 관심 있는 메서드의 반환값을 확인
assertEquals(42, resultA)
assertEquals(24, resultB)
assertEquals(18, resultC)
}
}
relaxed = true가 설정된 값이 어떤 값이 반환되는지 확인하기 위해 다음 코드를 실행해보자.
class ManyGetUseCaseTest {
@Test
fun `test relaxed = true makes what kind of return value`() {
// Mockk 모의 객체 생성 (relaxed 모드)
val mockRepository = mockk<ManyGetRepository>(relaxed = true)
// Mock Repository의 메서드 동작 설정
every { mockRepository.getA() } returns 42
every { mockRepository.getB() } returns 24
every { mockRepository.getC() } returns 18
// 테스트 대상 객체 생성
val useCase = ManyGetUseCase(mockRepository)
//
println("getE() >> ${mockRepository.getE()}")
}
}
그러면 getE()에 대한 반환값이 0으로 설정된 것을 볼 수 있다. 만약 반환값이 리스트 형태였다면 빈 리스트가 반환되며, 문자열 타입이었다면 빈 문자열이 반환된다.
정리
relaxed = true를 사용하면 목 객체를 기본적으로 Dummy로 만들 수 있다. 물론 Dummy로 만들어진 목 객체에 추가적인 응답을 설정하는 것도 가능하다.