AndroidプロジェクトでKotlin Mockitを使うメモ
参考資料
Mocking and verifying · nhaarman/mockito-kotlin Wiki
Kotlin with Mockito | Baeldung
build.gradle
以下の依存を追加する
build.gradle
dependencies {
...
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.0.0-RC1'
testImplementation 'org.mockito:mockito-android:2.22.0'
...
Mock
モックとは
mockメソッドを使うと、そのクラスの実装に依存しないモックオブジェクトを生成します。
各メソッドの戻り値はモックオブジェクトになりますが、指定したメソッドの戻り値だけを任意に設定できます。
Mockito 初めの一歩
例
実行結果を上書きする
関数test1()
の実行結果を上書きする
テストコード
@Test
fun test1(){
val testClass = mock<MyTestClass> {
on{testFunction()} doReturn "mock response"
}
assertEquals("mock response",testClass.testFunction())
}
class MyTestClass{
fun testFunction():String{
return "testCalling inside"
}
}
実行結果を上書きする(呼び出しごとに変化する)
関数test1()
の実行結果を上書きするが、呼び出しごとに順番に返却する値を変える。
テストコード
@Test
fun testList(){
val testClass = mock<TestClass> {
on{test()} doReturn listOf<String>("1","2","3")
}
assertEquals("1",testClass.test())
assertEquals("2",testClass.test())
assertEquals("3",testClass.test())
}
class MyTestClass{
fun testFunction():String{
return "testCalling inside"
}
}
コールバックインターフェースが呼ばれたか確認する
インターフェースTestInterface
をモック、TestClassにそのモックインターフェースを渡す。
そのときインターフェースのonUpdate
が呼ばれていることを確認する。
テストコード
@Test
fun test(){
val testIf : TestInterface = mock()
val testClass = TestClass(testIf)
testClass.test()
verify(testIf).onUpdate("mocked update") // TestInterface.onUpdateに("haha")が渡された状態になっているか
}
interface TestInterface{
fun onUpdate(str:String)
}
class TestClass(val myIf:TestInterface){
fun test():String{
myIf.onUpdate("mocked update") // onUpdate実行、"mocked update"返却。
return "this is test."
}
}
コールバックインターフェースの実行結果を上書きする
テストコード
@Test
fun test5(){
val TEST_STRING = "Can I Create?"
val EXPECTED_RESULT = "Success"
val testIf : TestInterface = mock()
whenever(testIf.create(TEST_STRING)).thenReturn(EXPECTED_RESULT) // インターフェースにTEST_STRINGが渡されたとき、EXPECTED_RESULTを返却するモックを作成
val testClass = TestClass(testIf)
val result = testClass.testCreate(TEST_STRING)
verify(testIf).create(TEST_STRING) // インターフェースが、渡した値で呼ばれているか
assertEquals(EXPECTED_RESULT, result) // testCreate()の返り値を確認。 ( ≒ whenever節で設定した値でインターフェースが返却されたか )
}
interface TestInterface{
fun create(str:String):String
}
class TestClass(val myIf:TestInterface){
fun testCreate(str: String):String{
return myIf.create(str)
}
}
Spy
一部のメソッドの実行結果のみを上書きし、それ以外はもともとの実装を利用する。
spyメソッドを使うと、任意のインスタンスの一部だけモックできます。
spyで得たオブジェクトは、モックしたメソッドの他は元々の実装で動作します。
Mockito 初めの一歩
テスト対象コードとテストコード
@Test
fun spy1(){
val spiedClass = spy(XP1DataTransportClientService.TestClass2())
spiedClass.testCall()
verify(spiedClass).testCall2()
}
class TestClass2(){
fun testCall(){
testCall2()
}
fun testCall2(){
}
}
テスト対象コードとテストコード
@Test
fun passAnyStringToSpy() {
/* Given */
val my = spy(MyClass())
/* When */
doReturn("mocked").whenever(my).foo(any())
/* Then */
expect(my.foo("hello")).toBe("mocked")
}
private interface MyInterface {
fun foo(value: String): String
}
private open class MyClass : MyInterface {
override fun foo(value: String): String = value
}
いまさら聞けなかったこと
- Mockitoが使えるのはUnit Testのみ。Instrumentation Testは不可。
-
Log.d(...)
ではUnit Testではログは出力されない(あたりまえか)。printlnで。