Mockito로 여러 개의 method 모듈을 만들 때 주의사항

사용하는 JUNIt는 JUNIt4입니다.

하고 싶은 일


예를 들어, CatRepository라는 class가 NyaoDataSource라는 class에 의존한다고 가정해 봅시다.
이때
CatRepository.kt
@RunWith(MockitoJUnitRunner::class)
class CatRepository @Inject constructor(
    val nyaoDataSource: NyaoDataSource
): CatRepository {
    // 指定の猫が鳴けるかどうかを確認する
    override suspend fun getChirp(baseCat: BaseCat): CatInfo {
        if (nyaoDataSource.checkChirp(baseCat.nameCat) == true) {
            return nyaoDataSource.getChirp(baseCat.nameCat)
        }
        throw IllegalStateException("This cannot chirp...sorry.")
    }
}
이렇게 쓸 수 있지만 이method를 테스트하려면 nyaoDataSource.checkChirpnyaoDataSource.getChirp 두 개의 모델로 테스트해야 한다.
그래서 이번에 하고 싶은 것은'모키토로 여러 메트로이드를 적절히 만드는 모듈'이다.

최초로 제작된 코드(의외의 동작을 한 코드)


우선 의외의 동작을 한 코드입니다.
CatRepositoryTest.kt
...中略
    private val mockNyaoLocal = mock(NyaoDataSource::class.java)
    @Test
    fun getAuthInfoTest() {
        runBlocking {
            val inputDummy = BaseCat(
                nameCat = "Tama",
                cate = "mike",
            )
            mockNyaoLocal.apply {
                `when`(checkChirp(inputDummy.nameCat)).thenReturn(false)
                `when`(getAccountInfo(inputDummy.nameCat))
		    .thenThrow(IllegalArgumentException("この猫はいない。いるかどうか、チェックしてから使ってね."))
            }

            val catRepositoryImpl = CatRepositoryImpl(mockNyaoLocal)
            val e: IllegalStateException 
	        = assertThrows(IllegalStateException::class.java){
                runBlocking {
                    catRepositoryImpl.getChirp(inputDummy)
                }
            }
	    assertEquals("この猫はいないよ。",
            e.message)
        }
    }
}
이 결과는 반드시 통과해야 할 테스트는 통과하지 못한다.왜냐면,CatRepository.kt의if문에서의 처리도 집행되었다(실제로 집행된 것이 아니라 그 행위는 다음과 같은 추측이다).
여기서 이상한 것은CatRepositoryTest입니다.kt에서.
 mockNyaoLocal.apply {
                `when`(checkChirp(inputDummy.nameCat)).thenReturn(false)
                `when`(getAccountInfo(inputDummy.nameCat))
		    .thenThrow(IllegalArgumentException("この猫はいない。いるかどうか、チェックしてから使ってね."))
            }
이 부분.when의 어떤 조건에 부합되면 apply의 모든 것이 실행됩니다.Mockito의 Reference를 찾아보았지만 좋은 것을 찾지 못했고 apply의 행동을 조사한 결과[1][2]는 이해하기 어려웠기 때문에 제 추측이 정확한지 누가 알려주면 좋겠어요.

이동 코드


이동하는 코드는 다음과 같습니다.
CatRepositoryTest.kt
...中略
    private val mockNyaoLocal = mock(NyaoDataSource::class.java)
    @Test
    fun getAuthInfoTest() {
        runBlocking {
            val inputDummy = BaseCat(
                nameCat = "Tama",
                cate = "mike",
            )
            doReturn(false)
                .`when`(mockNyaoLocal)
                .checkChirp(inputDummy.nameCat)
            doReturn(IllegalArgumentException("この猫はいない。いるかどうか、チェックしてから使ってね."))
                .`when`(mockNyaoLocal)
                .getChirp(inputDummy.nameCat)

            val catRepositoryImpl = CatRepositoryImpl(mockNyaoLocal)
            val e: IllegalStateException 
	        = assertThrows(IllegalStateException::class.java){
                runBlocking {
                    catRepositoryImpl.getChirp(inputDummy)
                }
            }
	    assertEquals("この猫はいないよ。",
            e.message)
        }
    }
}
방금 잘 돌아가지 못한 코드
(으)로 변경합니다.이렇게 하면 각자의 when이 독립적으로 움직여 기대하는 운동을 실현할 수 있다.
하지만 stub를 사용하지 않아 컴파일러에게 욕을 먹기 때문에 이번에는 아래의 Exception이 필요하지 않다.
각주
Kotlin 역할 영역 함수 용도 요약/@ngswtarohttps://qiita.com/ngsw_taro/items/d29e3080d9fc8a38691e(2022-01-16열람)↩︎
Kotlin의 let (), apply (),run (), with () 를 자유롭게 사용하기/Masamichii Yoshii http://extra-vision.blogspot.com/2016/11/kotlin-let-apply-run-with.html ↩︎

좋은 웹페이지 즐겨찾기