0Pricing
Android Academy · レッスン

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 call

verify() — やり取りの確認

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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. JUnitによるユニットテスト
  2. Mockitoによるモック
  3. EspressoによるUIテスト
  4. デバッグとプロファイリング
← Android Academyに戻る