Mockitoによるモック
MockitoとMockKで依存関係を分離します。戻り値をスタブし、インタラクションを検証し、引数をキャプチャして、部分的なモックにスパイを使います。
「Mockitoによるモック」はCoddyKit上の無料Android Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAndroid Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Android Academyコースには全4レッスンが含まれています。
モックとは何ですか?
mockは、テストで実際の依存関係を置き換える偽のオブジェクトです。動作するメモリ上の実装であるFakeとは異なり、mockには次の特徴があります:
- ライブラリによって自動生成されます
- どのメソッドがどの引数で呼び出されたかを記録します
- 指定した値を返します(stubbing)
- テスト後にやり取りをverifyできます
Mockitoのセットアップ
MockitoとMockK(Kotlinに最適化された代替ライブラリ)をapp/build.gradleに追加します:
// app/build.gradle:
testImplementation 'org.mockito:mockito-core:5.10.0'
testImplementation 'org.mockito.kotlin:mockito-kotlin:5.2.1'
// MockK (Kotlin-idiomatic alternative to Mockito):
testImplementation 'io.mockk:mockk:1.13.10'Mockの作成
mock()または@Mockアノテーションを使用してMockを作成します:
import org.mockito.kotlin.*
interface UserApi {
suspend fun fetchUsers(): List<User>
suspend fun deleteUser(id: Int)
}
class RepositoryTest {
// Option 1: create inline
private val api: UserApi = mock()
// Option 2: use annotation + MockitoJUnit4Runner
@Mock lateinit var api2: UserApi
@get:Rule
val mockitoRule = MockitoJUnit.rule()
}スタブ化 — 戻り値の定義
whenever(mock.method()).thenReturn(value)を使用して、Mockが返す値を設定します:
val api: UserApi = mock()
// Stub a return value:
whenever(api.fetchUsers()).thenReturn(
listOf(User(1, "Alice"), User(2, "Bob"))
)
// Stub an exception:
whenever(api.fetchUsers()).thenThrow(RuntimeException("Network error"))
// Return different values on consecutive calls:
whenever(api.fetchUsers())
.thenReturn(emptyList()) // first call
.thenReturn(listOf(User(1, "Alice"))) // second callverify() — やり取りの確認
verify()を使用して、メソッドが呼び出されたことと、その回数をアサートします:
val api: UserApi = mock()
val repo = UserRepository(api)
repo.refreshUsers()
// Verify that fetchUsers() was called exactly once:
verify(api).fetchUsers()
// Verify called with specific argument:
repo.deleteUser(42)
verify(api).deleteUser(42)
// Verify called exactly 3 times:
verify(api, times(3)).fetchUsers()
// Verify never called:
verify(api, never()).deleteUser(any())ArgumentCaptor
ArgumentCaptorは、Mockのメソッドに渡された引数を取得するため、値をアサートできます:
val api: UserApi = mock()
val captor = argumentCaptor<User>()
val repo = UserRepository(api)
repo.saveUser(User(1, "Alice"))
verify(api).saveUser(captor.capture())
val captured = captor.firstValue
assertEquals(1, captured.id)
assertEquals("Alice", captured.name)MockK — Kotlinに最適化されたモック
MockKはKotlin向けに設計されており、拡張関数、コルーチン、オブジェクトをネイティブに扱えます:
import io.mockk.*
val api = mockk<UserApi>()
// Stub:
every { api.fetchUsers() } returns listOf(User(1, "Alice"))
// Stub suspend function:
coEvery { api.fetchUsers() } returns listOf(User(1, "Alice"))
// Verify:
val repo = UserRepository(api)
runBlocking { repo.refresh() }
coVerify { api.fetchUsers() }MockKによるコルーチンのモック
suspend関数にはcoEveryとcoVerifyを使用します:
val api = mockk<UserApi>()
// Stub suspend function:
coEvery { api.fetchUsers() } returns listOf(User(1, "Alice"))
coEvery { api.deleteUser(any()) } just Runs // returns Unit
// Test:
runTest {
val repo = UserRepository(api)
repo.refresh()
coVerify(exactly = 1) { api.fetchUsers() }
coVerify(exactly = 0) { api.deleteUser(any()) }
}Spy — 部分的なモック
spyは実際のオブジェクトをラップします。上書きしない限り、デフォルトでは実際のメソッドが呼び出されます:
// Mockito Spy:
val realList = mutableListOf("a", "b", "c")
val spyList = spy(realList)
// Real method called:
spyList.add("d")
assertEquals(4, spyList.size) // real add() was called
// Override specific method:
doReturn(99).`when`(spyList).size
assertEquals(99, spyList.size) // overridden
// MockK Spy:
val spyObj = spyk(RealService())
every { spyObj.expensiveCall() } returns "fake result"MockとFakeの使い分け
実践的な指針です:
- Fakeを使用する:動作するメモリ上の実装(DAO、リポジトリ)が必要な場合。読みやすく、ライブラリも必要ありません
- Mockを使用する:特定のメソッドが特定の引数で呼び出されたことを検証する必要がある場合(分析イベント、API呼び出し)
- Mockの使いすぎを避ける:すべてをMockにすると、テストしているのはロジックではなくMockになってしまいます
よくある間違い
モックを使用する際に避けるべき落とし穴です:
- 値オブジェクトをMockにする — データクラスではなく、インターフェースや抽象化をMockにします
- 深くMockにしすぎる — 1つのテストで5つのMockが必要なら、コードの結合度が高すぎます
- やり取りが重要なのに検証しない — スタブ化するだけでなく、検証も行います
- MockitoとKotlinのデフォルト — Kotlinのパラメーターはデフォルトでnull非許容です。予期しないnullを避けるには
mockito-kotlinまたはMockKを使用します
オブジェクトとコンパニオンオブジェクトのモック
MockKでは、KotlinのオブジェクトとコンパニオンオブジェクトをMockにできます。これはMockitoでは不可能です:
object DateProvider {
fun today(): String = "2024-01-01"
}
// In test:
mockkObject(DateProvider)
every { DateProvider.today() } returns "2099-12-31"
val result = DateProvider.today()
assertEquals("2099-12-31", result)
// Restore after test:
unmockkObject(DateProvider)確認問題
MockitoまたはMockKのテストにおけるverify()の役割は何ですか?
まとめ:MockitoとMockKによるモック
Mockを使うと、動作を分離して検証できます:
mock()/mockk()— インターフェースまたはクラスからMockを作成しますwhenever(...).thenReturn(...)/every { } returns ...— 戻り値をスタブ化しますcoEvery/coVerify— Kotlinのsuspend関数に使用します(MockK)verify(mock).method(args)— メソッドが呼び出されたことをアサートしますArgumentCaptor— 引数を取得して検査しますspy()/spyk()— 実際のオブジェクトを部分的にMockにします- データにはFakeを優先し、動作の検証にはMockを使用します
次は、EspressoによるUIテストです。
よくある質問
「Mockitoによるモック」レッスンは無料ですか?
はい。「Mockitoによるモック」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Android Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Android Academyコースには全4レッスンが含まれています。
「Mockitoによるモック」で何を学びますか?
MockitoとMockKで依存関係を分離します。戻り値をスタブし、インタラクションを検証し、引数をキャプチャして、部分的なモックにスパイを使います。 ブラウザで直接実行するハンズオンコードでAndroid Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Android Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAndroid Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「Mockitoによるモック」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAndroid Academyレッスンでコードを書いて実行できますか?
はい。すべてのAndroid Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- JUnitによるユニットテスト
- Mockitoによるモック
- EspressoによるUIテスト
- デバッグとプロファイリング