지금 까지 테스트 관련 포스트를 다뤄오면서
mock 객체 사용을 지양하자고 계속 해서 다뤄왔습니다.
하지만! 그럼에도 불구하고 mock 객체를 활용해야하는 순간이 있습니다.
함께 보시죠.
바로 다른 모듈에 대한 정보가 없을 때 입니다.
무슨 상황이냐고요?
클린 아키텍처를 살펴봅시다.
presentation과 data는 최소한 인터페이스가 아닌 클래스들을 가지고 있겠지만
domain은 최소한의 클래스와 인터페이스로 구성된 Layer입니다.
domain은 추상화된 인터페이스를 가지고 있고 구현체는
data에서 관리합니다.
domain은 data에 대한 구체적인 정보가 없고 오로지 자기 자신밖에 모릅니다.
그럼 domain은 어떻게 테스트 할까요?
구체적인 구현체도 없고 오로지 Interface랑 모델 및 기타 클래스 밖에없는데...
이때 주로 Mockito를 사용합니다.
testImplementation ("io.mockk:mockk:1.12.0")
androidTestImplementation ("io.mockk:mockk-android:1.12.0")
의존성을 App Gradle에 추가해줍시다.
테스트할 Usecase
class AddNumbersUseCase @Inject constructor(private val calculator: Calculator) {
operator fun invoke(a: Int, b: Int) = calculator.add(a, b)
}
calculator는 domain layer라 구현정보는 없는 인터페이스입니다.
class MockCalculatorTest {
//1. Mocking 할 객체에 어노테이션 추가
@MockK
lateinit var usecase: AddNumbersUseCase
//2. 어노테이션 초기화
@Before
fun setUp() {
MockKAnnotations.init(this)
}
@Test
fun `숫자를_더한다`() {
//Given
val a = 1
val b = 2
//3. When
//Mock 객체 사용전 행동 지정
every { usecase.invoke(a, b) } returns 3
val result = usecase.invoke(a, b)
//Then
assertEquals(3, result)
}
}
1 ~ 3번 과정을 통해 Mock 객체가 사용 가능해집니다.
every { usecase.invoke(a, b) } returns 3
모든 usecase.invoke(1, 2) 는 3을 반환합니다.
사용법 굉장히 간단하죠?
테스트를 실행하니 정상 동작합니다.
되도록이면 실제 객체를 통해 테스트하고
불가피 하다면 그때 Mockito를 사용 하는 것이 맞다고 생각합니다.
Mockito는 실제 객체의 행동을 흉내낼 뿐 실제 객체가 아닙니다.
테스트를 했을 때 테스트는 통과하지만 실제로는 동작 실패하는 경우가 생길 수도 있습니다.
다른 모듈에 의존성을 가지지 않고 주로 인터페이스로 이루어진
domain같은 모듈에만 사용하는게 좋겠죠?
최대한 실제객체로 테스트 합시다!