mcpField
C
configuring-test-dependencies

configuring-test-dependencies

github.com/skydovesテスト・品質33962 回インストール22 週間前に更新
リポジトリ

configuring-test-dependencies について

Android Compose プロジェクトの保守担当者向けに、デバイステストと Robolectric のホストテストで必要な Gradle 依存関係と設定先を説明するスキルです。テスト用マニフェスト、Lint 警告、アクセシビリティチェックの依存関係も扱います。

主な機能

  1. 01デバイスとホストのテスト依存関係を区別
  2. 02ui-test-manifest の設定先を指定
  3. 03ComponentActivity の起動要件を解説
  4. 04TestManifestGradleConfiguration 警告を説明
  5. 05アクセシビリティチェックの依存関係を提示

活用シーン

  1. 01Compose テストの Activity 起動失敗を修正
  2. 02createComposeRule が解決されない問題への対応
  3. 03Robolectric テストの依存関係を補完
  4. 04TestManifestGradleConfiguration 警告の調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/skydoves/android-testing-skills --skill configuring-test-dependencies

インストール後、Claude Code で/configuring-test-dependenciesを入力して読み込まれたか確認します。

詳細

テスト依存関係の設定 — Gradle のマトリックスを正しく構成する

Compose UI テストは、依存関係レイヤーで予測可能な 3 つの原因により失敗します。JUnit4 の構成が誤ったソースセットにある、ui-test-manifest アーティファクトが不足しているか誤った構成にある、またはホストテスト用の 3 つの依存関係が揃っていない、のいずれかです。このスキルでは、正確なマトリックスと、それをチェックする lint 警告を定義します。後続のスキル(choosing-test-rule-vs-runtest/SKILL.md、setting-up-host-vs-device-tests/SKILL.md)では、依存関係が正しく設定されていることを前提とします。

このスキルを使う場面

  • ユーザーから java.lang.RuntimeException: Could not launch activity within 45 seconds. Examined activities: ... androidx.activity.ComponentActivity または ActivityNotFoundException が報告された場合。
  • IDE で createComposeRule が未解決として示されるか、import androidx.compose.ui.test.junit4.createComposeRule が赤く表示される場合。
  • lint が build.gradle.kts の行に TestManifestGradleConfiguration(重大度 WARNING)を表示する場合。
  • ユーザーが Compose の Robolectric/ホスト(JVM)テストを追加しようとしており、依存させるアーティファクトを尋ねている場合。
  • ユーザーが enableAccessibilityChecks(...) を使いたいものの、どのアーティファクトに含まれているか分からない場合。

このスキルを使わない場面

  • 依存関係はすでに正しく、ユーザーが createComposeRule() と runComposeUiTest { } のどちらを使うか選んでいる場合は、./choosing-test-rule-vs-runtest/SKILL.md を使います。
  • 依存関係はコンパイルできるものの、テストが誤ったソースセット(test/ と androidTest/)で実行される場合は、./setting-up-host-vs-device-tests/SKILL.md を使います。
  • テストはコンパイル・実行できるものの、不安定またはタイムアウトする場合は、../../synchronization/synchronizing-with-idle/SKILL.md から始めます。

前提条件

  • com.android.application または com.android.library プラグインが適用された Android Gradle Plugin。
  • Compose が有効なモジュール(org.jetbrains.kotlin.plugin.compose プラグイン、または buildFeatures.compose = true)。
  • テストクラスパスに JUnit4 依存関係があること(Compose の ui-test-junit4 アーティファクトは引き続き JUnit4 を使用します。JUnit5 にはサードパーティ製の Vintage エンジンブリッジが必要ですが、ここでは対象外です)。

ワークフロー

  • 1. モジュールに必要なテストの種類を決めます。 一般的な Compose 機能モジュールでは、スクリーンショット/RenderThread/フルスタックのテストを行うインストルメンテーションテスト、高速なロジック検証を行うホスト(Robolectric)テスト、そして createComposeRule() 用のマニフェストヘルパーの 3 つが必要です。ステップ 2 のマトリックスから選びます。

  • 2. 正しい構成に依存関係を追加します。 モジュールの build.gradle.kts に次の内容をコピーします。

dependencies {
    // --- Instrumentation tests (src/androidTest/) ---
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    // MUST be debugImplementation (see Pattern: WRONG vs RIGHT for ui-test-manifest below)
    debugImplementation("androidx.compose.ui:ui-test-manifest")

    // --- Host tests with Robolectric (src/test/) ---
    testImplementation("androidx.compose.ui:ui-test")            // common test API
    testImplementation("androidx.compose.ui:ui-test-junit4")     // ComposeTestRule + createComposeRule
    testImplementation("androidx.compose.ui:ui-test-manifest")   // ComponentActivity manifest entry
    testImplementation("org.robolectric:robolectric:4.13")       // pin a version

    // --- Optional: accessibility validation (API 34+) ---
    androidTestImplementation("androidx.compose.ui:ui-test-junit4-accessibility")
    // Or, when using runComposeUiTest { } (no Rule):
    androidTestImplementation("androidx.compose.ui:ui-test-accessibility")
}

正確な GA バージョンは Compose UI BOM または開発者が選んだ composeVersion に従います。Robolectric は Compose BOM に含まれないため、個別にバージョンを固定します。

  • 3. テストが androidx.activity.ComponentActivity に対する ActivityNotFoundException で失敗する場合、99 パーセントはマニフェストアーティファクトが原因です。 このアーティファクトは単一ファイルのライブラリで、compose/ui/ui-test-manifest/src/main/AndroidManifest.xml にある次の <activity> エントリーをテスト APK のマニフェストにマージします。
<activity android:theme="@android:style/Theme.Material.Light.NoActionBar"
    android:name="androidx.activity.ComponentActivity" android:exported="true" />

このエントリーがないと、createComposeRule() と runComposeUiTest { } はどちらもデフォルトで ActivityScenario.launch を介して androidx.activity.ComponentActivity を起動するため、起動時にクラッシュします。原因を特定するには、次を確認します。

  • ui-test-manifest が依存関係の一覧に含まれていることを確認します。

  • debugImplementation(ホストテストの場合は testImplementation)に設定されていることを確認します。androidTestImplementation に設定されている場合、lint は警告を出しますが、Gradle は依存関係を引き続き組み込みます。ただし、AGP のバリアントモデルでは debug と androidTest のマニフェストマージが意図的に分離されています。そのため、androidTestImplementation に設定しても、インストルメンテーションテストの実行対象となるホスト APK に <activity> はマージされません。この lint チェックは、まさにこれを検出するためのものです。

  • 4. TestManifestGradleConfiguration の lint 警告に対処するため、依存関係を debugImplementation に移動します。 lint チェックは compose/ui/ui-test-manifest-lint/src/main/java/androidx/compose/ui/test/manifest/lint/GradleDebugConfigurationDetector.kt にあります。重大度は Severity.WARNING で、クイックフィックスでは設定名を debugImplementation に置き換えます。このチェックは、成果物が implementation、api、compileOnly、runtimeOnly、androidTestImplementation、testImplementation、または android/test/サポートされている設定名のいずれかで始まるカスタム設定に指定されている場合に発生します。

  • 5. マニフェストの成果物が本当に必要かどうかを判断します。 次の場合に必要です。

    • テストで createComposeRule() を使用する(型パラメーターなし — デフォルトは androidx.activity.ComponentActivity)。
    • テストで runComposeUiTest { } を使用する(型パラメーターなし — 同じデフォルト)。

    次の場合には不要です。

    • テストで createAndroidComposeRule<MyActivity>() を使用し、開発者自身が src/androidTest/AndroidManifest.xml(または src/debug/AndroidManifest.xml)に <activity android:name=".MyActivity" .../> を宣言している。
    • テストで createEmptyComposeRule() を使用し、本番マニフェストですでに宣言されている Activity に対して独自の ActivityScenario を起動する。
  • 6. ホストテストでは、3 つすべての成果物が testImplementation に指定されていることを確認します。 Robolectric は JVM の Looper を制御しますが、Compose のアイドリングおよびクロックの実装には ui-test(共通)と ui-test-junit4(ComposeTestRule インターフェースおよび createComposeRule の実装)の両方が必要です。ui-test-manifest が testImplementation に指定されていないと、同じマニフェストを解析するため、Robolectric は同じ ActivityNotFoundException をスローします。androidx 自体のホストソースセットでもこの設定を使用しています — compose/ui/ui-test/src/androidHostTest/kotlin/androidx/compose/ui/test/RobolectricComposeTest.kt を参照してください。

  • 7. 開発者が enableAccessibilityChecks を呼び出す予定がある場合にのみ、アクセシビリティの成果物を追加します。 これらは JUnit4 のサーフェスとは独立しています。

    • ui-test-accessibility は ComposeUiTest(runComposeUiTest { } のレシーバー)を拡張します。
    • ui-test-junit4-accessibility は ComposeTestRule/AndroidComposeTestRule を拡張します。 どちらも @RequiresApi(34) で、Robolectric では何も行いません(Build.FINGERPRINT == "robolectric" の場合、警告がログに記録されます)— 詳細は、このリポジトリのアクセシビリティスキルを参照してください。
  • 8. Gradle を同期して、テストを再実行します。 ./gradlew :app:connectedDebugAndroidTest(インストルメンテーション)または ./gradlew :app:testDebugUnitTest(ホスト)をクリーンな状態で実行すると、コンパイルされ、ComponentActivity が見つかるはずです。

パターン

パターン:誤りと正しい例 — ui-test-manifest の設定
// WRONG
dependencies {
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    androidTestImplementation("androidx.compose.ui:ui-test-manifest")
}
// WRONG because: lint emits TestManifestGradleConfiguration (WARNING) and the manifest
// merger does not pull the <activity> entry into the merged APK manifest from the
// androidTest source set. createComposeRule() crashes with ActivityNotFoundException.
// RIGHT
dependencies {
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-test-manifest")
}

lint チェックでは debugImplementation のみが明示的に許可され、それ以外のすべての設定に警告が出ます。GradleDebugConfigurationDetector.kt より:

"The androidx.compose.ui:ui-test-manifest dependency is needed for launching a
 Compose host, such as with createComposeRule. However, it only needs to be present
 in testing configurations therefore use this dependency with the debugImplementation
 configuration"
パターン:誤りと正しい例 — ホストテストの依存関係
// WRONG
dependencies {
    testImplementation("androidx.compose.ui:ui-test-junit4")
    testImplementation("org.robolectric:robolectric:4.13")
    // Missing ui-test-manifest -> ActivityNotFoundException at runComposeUiTest launch
    // Missing ui-test          -> linker errors on common test API symbols
}
// RIGHT
dependencies {
    testImplementation("androidx.compose.ui:ui-test")
    testImplementation("androidx.compose.ui:ui-test-junit4")
    testImplementation("androidx.compose.ui:ui-test-manifest")
    testImplementation("org.robolectric:robolectric:4.13")
}
パターン:誤りと正しい例 — 独自のマニフェストエントリーがないカスタム Activity
// WRONG
@get:Rule val rule = createAndroidComposeRule<MyHostActivity>()
// build.gradle.kts has only debugImplementation("androidx.compose.ui:ui-test-manifest")
// and src/androidTest/AndroidManifest.xml does NOT declare MyHostActivity.
// WRONG because: ui-test-manifest only declares ComponentActivity. Custom activities
// must be declared in the test APK manifest by the developer. Result: ActivityNotFoundException.

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <activity android:name=".MyHostActivity" android:exported="true" />
    </application>
</manifest>
パターン:build.gradle.kts の完全なサンプル
plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
    id("org.jetbrains.kotlin.plugin.compose")
}

android {
    namespace = "com.example.feature"
    compileSdk = 35
    defaultConfig {
        minSdk = 23
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    buildFeatures { compose = true }
    testOptions {
        unitTests.isIncludeAndroidResources = true   // required for Robolectric + Compose
    }
}

dependencies {
    val composeBom = platform("androidx.compose:compose-bom:2025.06.00")
    implementation(composeBom)
    androidTestImplementation(composeBom)
    testImplementation(composeBom)

    // Production
    implementation("androidx.compose.ui:ui")
    implementation("androidx.activity:activity-compose")

    // Instrumentation
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    debugImplementation("androidx.compose.ui:ui-test-manifest")
    androidTestImplementation("androidx.test.ext:junit:1.2.1")
    androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1")

    // Host (Robolectric)
    testImplementation("androidx.compose.ui:ui-test")
    testImplementation("androidx.compose.ui:ui-test-junit4")
    testImplementation("androidx.compose.ui:ui-test-manifest")
    testImplementation("org.robolectric:robolectric:4.13")
    testImplementation("junit:junit:4.13.2")
}

testOptions.unitTests.isIncludeAndroidResources = true は、Compose コンテンツのホストテスト中に Robolectric がマージ済みリソースを読み取るために必要です。

必須ルール

  • 必ず、インストルメンテーションテストでは androidx.compose.ui:ui-test-manifest を debugImplementation に、ホストテストでは testImplementation に指定してください。androidTestImplementation、implementation、api には指定しないでください。
  • 必ず、createComposeRule / ComposeTestRule をインポートするテストと同じソースセットに ui-test-junit4 を指定してください。同じモジュール内で androidTestImplementation(インストルメンテーション)と testImplementation(ホスト)を併用しても問題ありませんが、誤ったテストクラスに指定するとコンパイルエラーになります。
  • 必ず、ComponentActivity 以外のテストホスト(カスタム Activity)を、src/androidTest/AndroidManifest.xml または src/debug/AndroidManifest.xml のテスト APK マニフェストで宣言してください。ui-test-manifest アーティファクトが宣言するのは androidx.activity.ComponentActivity のみです。
  • lintOptions { disable("TestManifestGradleConfiguration") } で TestManifestGradleConfiguration lint チェックを削除してはいけません。代わりにクイックフィックスを適用してください。このチェックは、テストが気付かないうちに失敗するのを防ぐためのものです。
  • リリース構成(releaseImplementation、implementation)に ui-test-manifest を指定してはいけません。このアーティファクトはテスト用の足場にすぎず、不要な <activity> エントリを本番 APK に含めてサイズを増やします。
  • 推奨: Compose BOM(androidx.compose:compose-bom)を利用し、すべての ui-test-* アーティファクトのバージョンに一貫性を持たせてください。Robolectric は独立しており、別途バージョンを固定します。
  • 推奨: シンボルがどのアーティファクトに属するか判断に迷ったら、推測するのではなく、コーパスから androidx/compose/ui/ui-test* パスを検索してください。参考資料を参照してください。

検証

  • ./gradlew :<module>:connectedDebugAndroidTest がコンパイルされ、androidx.activity.ComponentActivity に対する ActivityNotFoundException を起こさず実行される。
  • ./gradlew :<module>:lint で TestManifestGradleConfiguration が報告されない。
  • ホストテストで runComposeUiTest { } または createComposeRule() を使用しても、./gradlew :<module>:testDebugUnitTest がコンパイルされる。
  • 依存関係ブロックで、androidTestImplementation(インストルメンテーション)、debugImplementation(マニフェスト)、testImplementation(ホスト用の3つ)が明確に分けられている。
  • 開発者がアクセシビリティ関連のアーティファクトを追加した場合、インストルメンテーションテスト内で enableAccessibilityChecks(...) がコンパイル時に解決される。
  • テスト APK のマニフェストに <activity android:name="androidx.activity.ComponentActivity"/> のエントリが1つだけ含まれている(./gradlew :app:processDebugAndroidTestManifest を実行し、build/intermediates/.../AndroidManifest.xml を確認する)。

参考資料

  • Compose のテスト設定(Android Developers):https://developer.android.com/develop/ui/compose/testing#setup
  • Compose のテスト概要:https://developer.android.com/develop/ui/compose/testing
  • Compose UI リリースノート:https://developer.android.com/jetpack/androidx/releases/compose-ui
  • Compose Multiplatform のテスト:https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-test.html
  • compose/ui/ui-test-manifest-lint/src/main/java/androidx/compose/ui/test/manifest/lint/GradleDebugConfigurationDetector.kt — TestManifestGradleConfiguration の問題定義(重大度 WARNING、debugImplementation に変更するクイックフィックス)。
  • compose/ui/ui-test-manifest/src/main/AndroidManifest.xml — createComposeRule() が依存する、マージ対象の <activity android:name="androidx.activity.ComponentActivity"> エントリ。
  • compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/ComposeUiTest.android.kt — runComposeUiTest はデフォルトで ComponentActivity::class.java を起動します(184~197 行目)。
  • compose/ui/ui-test/src/androidHostTest/kotlin/androidx/compose/ui/test/RobolectricComposeTest.kt — Robolectric を使うホストテストクラスの基本構成(@RunWith(AndroidJUnit4::class) @Config(minSdk = RobolectricMinSdk))。
  • compose/ui/ui-test/src/androidHostTest/kotlin/androidx/compose/ui/test/Constants.kt — internal const val RobolectricMinSdk = 23。

コメント