mcpField
M
migrating-from-android-test-classes

migrating-from-android-test-classes

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

migrating-from-android-test-classes について

非推奨の Android プラットフォーム `android.test.*` クラスを AndroidX Test に置き換える移行ガイドです。旧式のテストを保守する開発者向けに、ランナー、基底クラス、アサーション、UI 操作の移行先を示します。

主な機能

  1. 01クラスごとの置き換え案内
  2. 02AndroidJUnitRunner への移行
  3. 03JUnit3 テストの JUnit4 化
  4. 04アサーションと UI 操作の置換
  5. 05テスト用コンテキストとモックの置換

活用シーン

  1. 01旧モジュールから `android.test.*` を除去
  2. 02テストを AndroidX ランナーへ移行
  3. 03Activity テストを ActivityScenario に変更
  4. 04MoreAsserts と TouchUtils の置換

インストール

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

$npx skills add https://github.com/skydoves/android-testing-skills --skill migrating-from-android-test-classes

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

詳細

android.test.* からの移行 — プラットフォームのレガシーテストクラスから AndroidX Test へ

Android SDK に含まれる android.test.* パッケージ(InstrumentationTestCase、ActivityInstrumentationTestCase2、AndroidTestCase、ServiceTestCase、MoreAsserts、TouchUtils、android.test.mock.*、…)は @Deprecated です。プラットフォームの Javadoc でも、すべてのクラスの移行先として AndroidX Test が案内されています。古いコードベースには今もこれらのクラスが残っており、JUnit4、Espresso、ActivityScenario、AndroidX ランナーへの移行を妨げています。このスキルでは、クラスごとの置き換え先と機械的な移行パターンを示します。

このスキルを使う場合

  • IDE が android.test.InstrumentationTestCase/AndroidTestCase/ActivityInstrumentationTestCase2/ServiceTestCase/MoreAsserts/ViewAsserts/TouchUtils/android.test.mock.* に @Deprecated の警告を表示する場合。
  • モジュールの testInstrumentationRunner が android.test.InstrumentationTestRunner で、AndroidJUnitRunner ではテストの動作がおかしい(または検出されない)場合。
  • ユーザーが特定のレガシーベースクラスの置き換え方法を尋ねている場合:「TestCase の外での getInstrumentation()」、「ActivityInstrumentationTestCase2 を使わずに getActivity()/setActivityIntent() を使う方法」、「AndroidTestCase を使わずに getContext() を使う方法」。
  • テストが junit.framework.TestCase を継承している(JUnit3 スタイル:setUp() のオーバーライド、testFoo() という命名、junit.framework.Assert の assertEquals)一方で、チームが JUnit4 を希望している場合。
  • ユーザーが MoreAsserts.assertContentsInAnyOrder/assertEquals(int[], int[])/assertContainsRegex、ViewAsserts.assertOnScreen、TouchUtils.tapView/dragQuarterScreenDown、または android.test.suitebuilder.annotation.SmallTest に言及している場合。

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

  • コードベースがすでに AndroidX Test を使用しており、質問がその使い方(ランナー、ActivityScenario、Espresso、ServiceTestRule)に関する場合は、../../../instrumentation/runner/running-instrumented-tests-with-androidjunit4/SKILL.md、../../../instrumentation/scenarios/launching-activities-with-activityscenario/SKILL.md、../../../instrumentation/espresso/writing-espresso-tests/SKILL.md を直接参照してください。
  • 質問が kotlin.test のアサーション(assertEquals、assertFailsWith)に関する場合は、../../../kotlin/kotlin-test/writing-tests-with-kotlin-test/SKILL.md を使ってください。(MoreAsserts の呼び出しを置き換える有効な選択肢の 1 つは kotlin.test です。)
  • 対象のレガシークラスが Robolectric のシャドウ、または純粋な JVM コードで使われる JUnit3 の 非 Android TestCase の場合は、JVM/Robolectric 側について ../../../jvm-tests/robolectric/using-robolectric-correctly/SKILL.md と ../../../jvm-tests/runner/configuring-junit4-on-android/SKILL.md を使ってください。
  • ユーザーが 新しい テストを書こうとしている場合は、最初から android.test.* を使わず、AndroidX のスキルを直接使ってください。

前提条件

  • テストクラスパスに AndroidX Test が含まれていること。必要な依存関係の正確な組み合わせ(androidx.test:core、:runner、:rules、androidx.test.ext:junit)については、../../../instrumentation/runner/running-instrumented-tests-with-androidjunit4/SKILL.md を参照してください。ホスト/JVM テストについては、../../../jvm-tests/runner/configuring-junit4-on-android/SKILL.md を参照してください。
  • クラスパスに JUnit4 が含まれていること(junit:junit:4.13.2、または kotlin("test") 経由)。レガシークラスは JUnit3 の形式です(TestCase を extends)。移行先は JUnit4(@Test と @RunWith)です。
  • TouchUtils/ViewAsserts/ActivityInstrumentationTestCase2 の UI 操作を使用していた機能には、Espresso(androidx.test.espresso:espresso-core)が必要です。

置き換え先一覧

レガシーの android.test.*(非推奨)代わりに使用備考
InstrumentationTestRunner(testInstrumentationRunner)androidx.test.runner.AndroidJUnitRunnerandroid.defaultConfig.testInstrumentationRunner を変更します。レガシーのランナーでは、JUnit4 や Espresso が正しく実行されません。
InstrumentationTestCase@RunWith(AndroidJUnit4::class) + InstrumentationRegistry.getInstrumentation()getInstrumentation() → androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()。injectInstrumentation(...) は廃止されています。sendKeys/runTestOnUiThread → getInstrumentation().runOnMainSync { … } または @UiThreadTest。
AndroidTestCase@RunWith(AndroidJUnit4::class) + ApplicationProvider.getApplicationContext()getContext() → ApplicationProvider.getApplicationContext<Context>()。getTestContext()(テスト APK のコンテキスト)→ InstrumentationRegistry.getInstrumentation().context。
ApplicationTestCase<T>@RunWith(AndroidJUnit4::class) を使用し、ApplicationProvider.getApplicationContext() を介して Application を操作します1 対 1 で置き換えられる基底クラスはありません。現在、Application は単なるコンテキストです。直接アサートしてください。
ActivityInstrumentationTestCase2<T>、ActivityUnitTestCase<T>、SingleLaunchActivityTestCase<T>ActivityScenario<T> / @get:Rule ActivityScenarioRule<T>(UI には Espresso も使用)getActivity() → scenario.onActivity { activity -> … }。setActivityIntent(intent) → ActivityScenario.launch<T>(intent)。getInstrumentation().waitForIdleSync() → Espresso の自動同期。../../../instrumentation/scenarios/launching-activities-with-activityscenario/SKILL.md を参照してください。
(独自実装の Fragment テストがある場合)FragmentScenario / launchFragmentInContainer../../../instrumentation/scenarios/launching-fragments-with-fragmentscenario/SKILL.md。
ServiceTestCase<T>androidx.test.rule.ServiceTestRulestartService(intent) / bindService(intent) はルールに移行します(@get:Rule val serviceRule = ServiceTestRule())。getService() → serviceRule.bindService(intent) から取得する IBinder。
ProviderTestCase2<T>androidx.test.rule.provider.ProviderTestRuleProviderTestCase2 は JUnit3 形式です。ProviderTestRule.Builder(MyProvider::class.java, AUTHORITY).build() が JUnit4 形式で、引き続き分離された ContentResolver を提供します。
LoaderTestCase(Loader 自体が非推奨です)まず Loader を ViewModel + コルーチン/Flow に移行し、その後 runTest / Turbine でテストしてください。
MoreAsserts(assertContentsInAnyOrder、assertEquals(int[], int[])、assertEmpty、assertNotEqual、assertContainsRegex、checkEqualsAndHashCodeMethods)Google Truth(assertThat(list).containsExactly(...)、.isEmpty()、.containsMatch(regex))、Hamcrest、または順序付き配列には kotlin.test.assertContentEqualsプラットフォームの Javadoc では「Hamcrest を使用」とされています。Truth のほうが読みやすいです。androidx.test.ext:truth には Android 固有の Truth サブジェクトが含まれています。
ViewAsserts(assertOnScreen、assertHorizontalCenterAligned、assertBottomAligned、…)Espresso の ViewMatchers + ViewAssertions(matches(isCompletelyDisplayed())、レイアウト関係を確認するカスタムマッチャー)../../../instrumentation/espresso/writing-espresso-tests/SKILL.md を参照してください。
TouchUtils(tapView、clickView、longClickView、dragQuarterScreenDown、scrollToBottom、dragViewToTop)Espresso の ViewActions(click()、longClick()、swipeUp()/swipeDown()、scrollTo()、GeneralSwipeAction)レガシーのメソッドには実行中の Instrumentation と Activity の参照が必要です。Espresso のアクションは onView(...).perform(...) 内で実行します。
android.test.UiThreadTestandroidx.test.annotation.UiThreadTestインポートを変更するだけです。または getInstrumentation().runOnMainSync { … } / scenario.onActivity { … }(すでにメインスレッド上で実行されます)に置き換えてください。
android.test.FlakyTestandroidx.test.filters.FlakyTestインポートを変更します。
android.test.suitebuilder.annotation.SmallTest / MediumTest / LargeTest / Suppressandroidx.test.filters.SmallTest / MediumTest / LargeTest / Suppressインポートを変更します。ランナーは AndroidX のアノテーションに対して -e size small を読み取ります。
android.test.InstrumentationTestSuite、android.test.suitebuilder.TestSuiteBuilderJUnit4 の @RunWith(Suite::class) + @Suite.SuiteClasses([...])、または AndroidJUnitRunner に @SmallTest/パッケージで検出させますAndroidX ランナーを導入すれば、手動でのスイート構築はほとんど必要ありません。
android.test.mock.MockContext実際のコンテキスト(ApplicationProvider.getApplicationContext())、JVM 上の Robolectric のコンテキスト、または厳密に分離する場合は mock(Context::class.java)(Mockito/MockK)MockContext はほとんどすべてのメソッドで UnsupportedOperationException をスローします。これは手動でスタブを実装するための基底クラスでしたが、モックフレームワークのほうが適しています。
android.test.mock.MockContentResolver + MockContentProviderProviderTestRule(分離されたリゾルバー)、または Robolectric/インストルメント化されたコンテキストから取得した実際の ContentResolverスタブのリゾルバーが本当に必要な場合は、Mockito で ContentResolver をモックしてください。
android.test.mock.MockPackageManagerMockito/MockK の mock(PackageManager::class.java)プラットフォームの Javadoc には「Mockito などのモックフレームワークを使用」と明記されています。
android.test.mock.MockResources / MockCursor / MockDialogInterface / MockApplication / MockServiceMockito/MockK のモック、またはテストコンテキストから取得した実際のインスタンス同様に、これらはスタブ用の基底クラスでしたが、モックフレームワークに置き換えられます。
android.test.AndroidTestRunner、android.test.PerformanceTestCase、android.test.RepetitiveTestAndroidJUnitRunner、androidx.benchmark(Microbenchmark/Macrobenchmark)、カスタム JUnit4 の @Rule、または単純なループPerformanceTestCase は androidx.benchmark よりも前のものです。本格的なパフォーマンステストには androidx.benchmark を使用してください。
extends junit.framework.TestCase + junit.framework.Assert の assertEquals(JUnit3 形式)@RunWith(AndroidJUnit4::class) + @Test メソッド + org.junit.Assert.* / kotlin.test.*メソッド名に test の接頭辞は不要になります。setUp/tearDown のオーバーライドは @Before/@After(または @BeforeTest/@AfterTest)になります。

プラットフォームの @deprecated Javadoc には、古い「Android Testing Support Library」/android.support.test.* の名前(例:ActivityTestRule)が記載されていることがよくあります。これらは androidx.test.* に移行され、その後、再び非推奨になったものもいくつかあります。たとえば、ActivityTestRule → ActivityScenario です。プラットフォームの Javadoc に文字どおり記載されているものではなく、上の表にある現在の移行先を使用してください。

ワークフロー

  • 1. まずランナーを切り替えます。 android.defaultConfig.testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" を設定し、AndroidX Test の依存関係を追加します。これが完了するまでは、JUnit4/Espresso/ActivityScenario を実行できません。(../../../instrumentation/runner/running-instrumented-tests-with-androidjunit4/SKILL.md。)

  • 2. テストクラスを1つずつ、JUnit3からJUnit4に変換します。 extends …TestCase を削除し、@RunWith(AndroidJUnit4::class) を追加して、テストメソッドに @Test を付けます。setUp()/tearDown() のオーバーライドを @Before/@After に変換し(super の呼び出しは不要です)、必要であれば testFoo を foo に名前変更します。各レガシーアクセサーを、表にあるAndroidXの同等機能に置き換えます。

  • 3. 基底クラスの特別な機能を、明示的なAndroidXのエントリーポイントに置き換えます。 getContext() → ApplicationProvider.getApplicationContext()、getInstrumentation() → InstrumentationRegistry.getInstrumentation()、getActivity() → ActivityScenario と onActivity { }、getService() → ServiceTestRule.bindService(...)。

  • 4. アサーションヘルパーを切り替えます。 MoreAsserts.* → Truth/kotlin.test、ViewAsserts.* → Espresso の ViewAssertions、TouchUtils.* → Espresso の ViewActions。

  • 5. モックコンテキストを切り替えます。 android.test.mock.MockContext/MockResources/MockPackageManager を継承するものは、可能であれば実際のテストコンテキストに置き換え、それ以外の場合はMockito/MockKのモックに置き換えます。(../../../jvm-tests/mocking/mocking-with-mockito/SKILL.md。)

  • 6. レガシーインポートを削除し、android.test.* や android.test.mock.* への参照が残っていないことを確認します。 モジュールがクリーンな状態であれば、import android.test. の行がゼロでもコンパイルできます。

パターン

パターン:ActivityInstrumentationTestCase2 → ActivityScenario
// WRONG — deprecated base class
class LoginActivityTest : ActivityInstrumentationTestCase2<LoginActivity>(LoginActivity::class.java) {
    fun testTitleShown() {
        val activity = activity                       // getActivity()
        assertEquals("Sign in", activity.title)
    }
}
// WRONG because: android.test.ActivityInstrumentationTestCase2 is @Deprecated; it ties the test to
// the legacy InstrumentationTestRunner, blocks JUnit4/Espresso, and getActivity() leaks the Activity
// off the main thread.
// RIGHT — ActivityScenario + JUnit4
@RunWith(AndroidJUnit4::class)
class LoginActivityTest {
    @get:Rule val scenario = ActivityScenarioRule(LoginActivity::class.java)

    @Test fun titleShown() {
        scenario.scenario.onActivity { activity ->
            assertEquals("Sign in", activity.title)
        }
        onView(withId(R.id.title)).check(matches(withText("Sign in")))   // or assert via Espresso
    }
}
パターン:AndroidTestCase → @RunWith(AndroidJUnit4) + ApplicationProvider
// WRONG
class FormatterTest : AndroidTestCase() {
    fun testCurrency() {
        val s = CurrencyFormatter(context).format(1099)   // getContext()
        assertEquals("$10.99", s)
    }
}
// WRONG because: android.test.AndroidTestCase is @Deprecated; getContext() and the TestCase shape
// are the legacy world.
// RIGHT
@RunWith(AndroidJUnit4::class)
class FormatterTest {
    private val context: Context = ApplicationProvider.getApplicationContext()

    @Test fun currency() {
        assertEquals("$10.99", CurrencyFormatter(context).format(1099))
    }
}
パターン:MoreAsserts/TouchUtils の呼び出し
// WRONG
MoreAsserts.assertContentsInAnyOrder(ids, 3L, 1L, 2L)         // android.test.MoreAsserts (deprecated)
TouchUtils.tapView(this, listView)                            // android.test.TouchUtils (deprecated)
ViewAsserts.assertOnScreen(rootView, listView)                // android.test.ViewAsserts (deprecated)
// RIGHT
assertThat(service.ids()).containsExactly(1L, 2L, 3L)         // Google Truth (order-insensitive)
onView(withId(R.id.list)).perform(click())                    // Espresso ViewActions
onView(withId(R.id.list)).check(matches(isCompletelyDisplayed()))   // Espresso ViewAssertions
パターン:android.test.mock.MockContext のサブクラス → 実際のコンテキストまたはMockito
// WRONG
class FakeContext : MockContext() {                            // android.test.mock.MockContext (deprecated)
    override fun getPackageName() = "com.example"
    // every other method throws UnsupportedOperationException
}
// RIGHT — a real test context if the SUT just reads from it
val context: Context = ApplicationProvider.getApplicationContext()

// RIGHT — a mock if you must control specific calls in isolation
val context = mock<Context> { on { packageName } doReturn "com.example" }

必須ルール

  • MUST NOT android.test.* または android.test.mock.* のクラスを使った新しいテストを追加しないでください。これらはすべて @Deprecated です。新しいテストでは AndroidX Test(AndroidJUnit4、ActivityScenario、ServiceTestRule、ProviderTestRule、Espresso)と、org.junit/kotlin.test のアサーションを使用してください。
  • MUST テストクラスの移行を始める前(または最初の手順として)に、testInstrumentationRunner を androidx.test.runner.AndroidJUnitRunner に切り替えてください。レガシーの InstrumentationTestRunner では JUnit4/Espresso を実行できません。
  • MUST getActivity()/setActivityIntent() を ActivityScenario(launch、onActivity { })に置き換えてください。ActivityTestRule には置き換えないでください。ActivityTestRule 自体も非推奨です。
  • MUST android.test.mock.MockContext/MockResources/MockPackageManager/MockContentResolver のサブクラスは、SUT が読み取りにしか使わない場合は実際のテストコンテキストに、それ以外の場合は Mockito/MockK のモックに置き換えてください。MockContext を基に新たな手作りのスタブを作り直さないでください。
  • MUST JUnit3 形式(extends TestCase、testFoo()、setUp()/tearDown() のオーバーライド、junit.framework.Assert)を JUnit4(@RunWith(AndroidJUnit4)、@Test、@Before/@After、org.junit.Assert/kotlin.test)に変換してください。クラスを中途半端に移行した状態にしないでください。
  • MUST NOT プラットフォームの @deprecated Javadoc に記載された置き換え先をそのまま信用しないでください(多くの場合、すでに廃止された android.support.test.* API が指定されています)。このスキルの表にある、現在の AndroidX の置き換え先に移行してください。
  • PREFERRED: 変更ごとにテストクラスを1つずつ完全に移行し、最初にランナーの切り替えを適用してください。一部のクラスが android.test.*、残りが AndroidX を使う中途半端な状態のモジュールは、把握が困難です。
  • PREFERRED: MoreAsserts の置き換えには、Hamcrest より Google Truth(Android のサブジェクトには androidx.test.ext:truth)を推奨します。失敗時のメッセージがより分かりやすくなります。

検証

  • git grep -n 'import android.test\.' -- '*.java' '*.kt' の結果が空であること(または、追跡対象で妥当な理由のある例外リストに限られていること)。
  • どのモジュールの testInstrumentationRunner も android.test.InstrumentationTestRunner ではなく、すべて androidx.test.runner.AndroidJUnitRunner であること。
  • extends ActivityInstrumentationTestCase2/AndroidTestCase/InstrumentationTestCase/ServiceTestCase/ProviderTestCase2/junit.framework.TestCase を使用するテストクラスがないこと。
  • MoreAsserts./ViewAsserts./TouchUtils. の参照が残っていないこと。
  • android.test.mock.MockContext/MockResources/MockPackageManager/MockContentResolver のサブクラスが残っていないこと。
  • 移行したインストルメンテーションテストが ./gradlew :module:connectedDebugAndroidTest で成功し、移行したホストテストが ./gradlew :module:testDebugUnitTest で成功すること。

参考資料

  • developer.android.com/training/testing — AndroidX Test の概要。android.test.* のすべての移行先です。
  • developer.android.com/reference/android/test/package-summary — android.test パッケージのリファレンス。すべてのクラスに非推奨のマークが付けられ、置き換え先が示されています。
  • frameworks/base/test-base/src/android/test/AndroidTestCase.java、InstrumentationTestCase.java、UiThreadTest.java、FlakyTest.java(AOSP) — @Deprecated クラスで、Javadoc には InstrumentationRegistry/androidx.test.annotation.UiThreadTest/androidx.test.filters.FlakyTest への移行先が記載されています。
  • frameworks/base/test-runner/src/android/test/ActivityInstrumentationTestCase2.java、ServiceTestCase.java、ProviderTestCase2.java、InstrumentationTestRunner.java、MoreAsserts.java、ViewAsserts.java、TouchUtils.java(AOSP) — 非推奨のランナー/基底クラスです。Javadoc では、置き換え先として ActivityTestRule/ServiceTestRule/AndroidJUnitRunner/Hamcrest/Espresso が挙げられています。
  • frameworks/base/test-mock/src/android/test/mock/MockContext.java、MockPackageManager.java、MockContentResolver.java、MockResources.java、MockCursor.java(AOSP) — スタブコンテキストの基底クラスです。MockPackageManager の Javadoc には、「Mockito のようなモックフレームワークを使用してください」と明記されています。
  • 横断参照:../../../instrumentation/runner/running-instrumented-tests-with-androidjunit4/SKILL.md — 最初に確認する AndroidJUnitRunner/AndroidX Test の対応バージョン表です。
  • 横断参照:../../../instrumentation/scenarios/launching-activities-with-activityscenario/SKILL.md — ActivityInstrumentationTestCase2 の置き換え先である ActivityScenario/ActivityScenarioRule です。
  • 横断参照:../../../instrumentation/scenarios/launching-fragments-with-fragmentscenario/SKILL.md — 独自のフラグメントテスト基底クラスに使用できる FragmentScenario です。
  • 横断参照:../../../instrumentation/espresso/writing-espresso-tests/SKILL.md — ViewAsserts/TouchUtils の置き換えとなる Espresso の ViewMatchers/ViewActions/ViewAssertions です。
  • 横断参照:../../../jvm-tests/mocking/mocking-with-mockito/SKILL.md — android.test.mock.* の置き換えとなる、Context/PackageManager/Resources のモック化です。
  • 横断参照:../../../jvm-tests/robolectric/using-robolectric-correctly/SKILL.md — モックコンテキストの代替となる、JVM 上での実際の Android スタブです。
  • 横断参照:../../../kotlin/kotlin-test/writing-tests-with-kotlin-test/SKILL.md — MoreAsserts と junit.framework.Assert の有効な置き換えの一つである、kotlin.test のアサーション(assertEquals、assertContentEquals、assertFailsWith)です。
  • 横断参照:../../../fundamentals/strategies/organizing-test-source-sets/SKILL.md — 移行したクラスを振り分ける src/test/ と src/androidTest/ です。

コメント