Robolectricは、エミュレーターや実機を使用せずにJVM上で直接テストを実行できるAndroidアプリケーション用の単体テストフレームワークです。Android SDKの呼び出しをインターセプトし、実際のコンポーネントの動作をエミュレートするシャドウオブジェクトを提供します。Robolectric Documentation, 2025によると、シャドウオブジェクトは約1万5千のAndroid APIクラスを置き換え、プラットフォームからテストを分離します。
重要ポイント
Robolectricは、2010年にAndroidアプリケーションテストを高速化するために作成されたオープンソースフレームワークです。エミュレーターやデバイス上で実行する代わりに、RobolectricはAndroid SDKクラスのシャドウ実装を提供し、Java仮想マシン(JVM)上で直接動作します。これにより、数千のテストを秒単位で実行できます。
従来のAndroidテストでは、エミュレーター上でアプリケーションを実行する必要があり、APKのビルド、インストール、起動に3〜10分かかります。Robolectricはこのステップを排除します。テストは通常のJava/Kotlinテストとしてコンパイルされ、JUnitを介して実行されます。これにより、分数ではなく秒単位のフィードバックループが実現します。
RobolectricはAPI 16(Android 4.1)から最新の安定版リリースまでのすべてのAndroidバージョンをサポートします。各バージョンに対して、アプリケーションがテストされているプラットフォームバージョンの動作をエミュレートする対応するシャドウオブジェクトのセットが提供されます。
Robolectricのアーキテクチャは、クラスローダーの置き換えによる呼び出しのインターセプトメカニズムに基づいています。テストがAndroid SDKのメソッドを呼び出すと、Robolectricがその呼び出しをインターセプトしてシャドウオブジェクトに転送します。シャドウオブジェクトは、Androidコンポーネントの実際の動作を模倣するJavaクラスですが、ネイティブプラットフォームなしで動作します。
シャドウオブジェクトは、元のAndroidクラスの主要メソッドを実装します。例えば、ShadowTextViewはgetText()、setText()、getCurrentTextColor()などのメソッドを模倣します。textView.setText("こんにちは")が呼び出されると、シャドウが文字列を保存し、getText()が呼び出されたときにそれを返します。これにより、テストを実際のレンダリングやシステムサービスから分離します。
Robolectricは、Android SDKの主要コンポーネント(Activity、Fragment、TextView、Button、RecyclerView、WebView、LocationManager、ConnectivityManagerなど)をカバーする200以上のシャドウクラスをサポートしています。シャドウオブジェクトは、元のAndroidクラスと同じ継承階層に従います。
GradleプロジェクトにRobolectricをインストールするには、依存関係testImplementation "org.robolectric:robolectric:4.x"を追加する必要があります。また、build.gradleファイルでandroidsdk設定を指定し、android:testInstrumentationRunnerを追加する必要があります。Robolectricを使用するためにAndroidテストプラグインは必要ありません。
依存関係を追加した後、マニフェスト、リソース、アセットのディレクトリを設定する必要があります。Robolectricは自動的にAndroidManifest.xmlを見つけますが、@Configアノテーションやシステムプロパティを使用してパスを手動で指定する必要がある場合があります。マルチモジュールプロジェクトの場合、設定はモジュールごとに個別に設定されます。
// build.gradle — Robolectricの設定
android {
testOptions {
unitTests.includeAndroidResources = true
unitTests.all {
systemProperty 'robolectric.dependency.dir',
project.rootDir.absolutePath + '/build/intermediates'
}
}
}
dependencies {
testImplementation 'org.robolectric:robolectric:4.13'
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0'
}
@Configアノテーションを使用すると、テストパラメーター(sdk:APIバージョン、manifest:マニフェストへのパス、qualifiers:画面設定、言語)を上書きできます。これは、異なるAndroidバージョン、画面の向き、ローカライゼーションでのアプリケーションの動作をテストするのに便利です。
Robolectricテストは、JUnit 4の場合は@RunWith(RobolectricTestRunner.class)、JUnit 5の場合はRobolectricExtensionを使用して通常の単体テストとして作成されます。ActivityControllerはActivityのライフサイクル(create()、start()、resume()、pause()、stop()、destroy())を管理します。これにより、各状態遷移を詳細にテストできます。
Activityをテストするには、ActivityControllerを使用し、ライフサイクルステージを順に通過します。Activityへのアクセスはcontroller.get()を介して行います。すべてのビューコンポーネントは、実際のアプリケーションと同様にfindViewByIdを介してアクセスできます。シャドウオブジェクトを使用すると、テキスト、可視性、色、その他のビュー属性を確認できます。
@RunWith(RobolectricTestRunner.class)
@Config(sdk = BuildConfig.SDK_INT)
public class MainActivityTest {
@Test
public void testActivityDisplaysGreeting() {
ActivityController<MainActivity> controller =
Robolectric.buildActivity(MainActivity.class);
controller.create().start().resume();
MainActivity activity = controller.get();
TextView greeting = activity.findViewById(R.id.greeting);
ShadowTextView shadow = Shadows.shadowOf(greeting);
assertEquals("Welcome!", shadow.getText());
}
}
RobolectricはstartActivity()呼び出しをインターセプトし、ShadowActivityを介して送信されたインテントを確認できます。これにより、ボタンをクリックしたときに正しいAction、Data、Extraパラメーターを持つIntentが送信されるかを検証するなど、ナビゲーションのテストが可能になります。
@Test
public void testNavigationToDetails() {
controller.create().start().resume();
MainActivity activity = controller.get();
activity.findViewById(R.id.detailsButton).performClick();
ShadowActivity shadowActivity = Shadows.shadowOf(activity);
Intent intent = shadowActivity.getNextStartedActivity();
assertEquals(
DetailsActivity.class.getName(),
intent.getComponent().getClassName()
);
}
Robolectricとエミュレーターは異なるタスクを解決します。Robolectricは高速な単体テスト、UIロジック、ビジネスコンポーネント、リポジトリの検証に最適です。エミュレーターはインストルメンテーションテスト、APIとの統合検証、カメラ、センサー、パフォーマンスのテストに必要です。
| 特性 | Robolectric | エミュレーター |
|---|---|---|
| 速度 | 100テストあたり約5秒 | 100テストあたり約5分 |
| 起動 | APKビルド不要 | APKビルドが必要 |
| リアルAPI | シャドウエミュレーション | ネイティブAndroid SDK |
| 標準機能 | JUnitのみ | 任意のフレームワーク |
Robolectricは、Android SDKを使用するが実際のUIを必要としないコンポーネント(ViewModel、Repository、UseCase)のテストに最適です。ViewModelはRobolectricExtensionを使用した通常のJUnitテストを介してテストされ、ライフサイクルコンポーネント(LiveData、StateFlow)はモックなしでシャドウ環境で動作します。
RobolectricはLiveDataを標準でサポートしています。テスト内でLiveDataを購読し、ViewModelを介して状態を変更し、発行された値を確認できます。非同期操作には、InstantTaskExecutorRuleまたはコルーチン用のrunBlockingを使用します。これにより、アーキテクチャコンポーネントをモックする必要がなくなります。
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [BuildConfig.SDK_INT])
class ProfileViewModelTest {
private val repository = FakeUserRepository()
private val viewModel = ProfileViewModel(repository)
@Test
fun `loading profile sets state to success`() = runBlocking {
viewModel.loadProfile("user123")
val state = viewModel.profileState.getOrAwaitValue()
Assertions.assertTrue(state is UiState.Success)
}
}
標準のRobolectricシャドウオブジェクトが必要なAndroid SDKクラスをカバーしない場合は、カスタムシャドウを作成できます。これを行うには、@Implements(ClassName.class)アノテーションを持つクラスを作成し、@Implementationで必要なメソッドを実装します。カスタムシャドウは@Config(shadows = [CustomShadow::class])を介して登録されます。
RobolectricはRobolectric.buildContentProvider()を介したContentProviderのテストをサポートしています。CRUD操作、URIマッチングによるクエリ、アクセス権限の処理を確認できます。リソース(文字列、色、寸法)はRuntimeEnvironment.application.resourcesを介してもアクセス可能で、リソースに依存するコードのテストが可能です。
インストルメンテーションテストからRobolectricへの移行には、アプローチの変更が必要です。インストルメンテーションテスト(AndroidJUnit4)はエミュレーター上で実際の動作を検証しますが、Robolectricはシャドウ環境で分離されたロジックを検証します。ビジネスロジックはRobolectricテストでカバーし、インストルメンテーションテストは統合シナリオ用に残すことを推奨します。
移行時には、AndroidJUnit4をRobolectricTestRunnerに置き換え、ターゲットSDKバージョンで@Configを追加し、ActivityTestRuleをActivityControllerに置き換え、依存関係をandroidTestImplementationからtestImplementationに移動します。モック(MockK、Mockito)は変更なしでRobolectricで動作します。これらはプラットフォームに依存しません。
Robolectricは以下をサポートしていません:カメラ(CameraX)、NFC、Bluetooth、生体認証、実際のファイルやネイティブライブラリの操作。これらのシナリオにはエミュレーターでのインストルメンテーションテストが必要です。Robolectricは実際のレンダリングも再現しません。レイアウトテストはCompose Test RuleまたはEspressoを介して行うのが良いでしょう。ただし、ビジネスロジック、ナビゲーション、ViewModel状態の検証に関しては、Robolectricは10倍の高速実行でエミュレーターを完全に置き換えます。
RobolectricにはJDK 11以上が必要で、AGP(Android Gradle Plugin)7.0から最新の安定版まで互換性があります。RobolectricのSDKマネージャーは、初回実行時に必要なAndroid APIバージョンを自動的にダウンロードします(一度きりの操作です)。CIサーバーの場合は、初回テスト実行時の遅延を避けるために、sdkmanagerを介してSDKを事前にロードすることを推奨します。Robolectricを新しいバージョンに更新する場合、通常はテストコードの変更は必要なく、build.gradleの依存関係番号を更新するだけです。
Robolectricは人気のあるモッキングフレームワークと互換性があります:Kotlin用のMockKとJava用のMockitoです。モックは依存関係(リポジトリ、APIクライアント、SharedPreferences)を分離するために使用されます。重要なルールは、Android SDKクラスをモックしないことです。そのためにはシャドウオブジェクトがあります。アプリケーション層(UseCase、Repository、DataSource、その他のビジネスロジックコンポーネント)のみをモックしてください。シャドウオブジェクトとモックのこの組み合わせにより、最小限のテスト作成労力で最大の柔軟性が得られます。
よくある質問
Espressoはエミュレーターまたはデバイス上で実行されるインストルメンテーションフレームワークです。RobolectricはJVM上で動作する単体テストフレームワークです。Espressoは実際の動作をテストし、Robolectricはシャドウ環境で分離されたロジックをテストします。両者は相互に補完します。
はい、Robolectricはバージョン4.8以降Jetpack Composeをサポートしています。Composeコンポーネントのテストは、エミュレーターと同様にComposeTestRuleを使用して実行されます。ただし、Robolectric上のComposeテストは実際のレンダリングをチェックせず、コンポジションロジックのみを検証します。
Robolectricはマルチモジュールプロジェクトをサポートしています。各モジュールは独自のマニフェストとリソースで個別に設定されます。UIコンポーネントのないモジュールの場合は、Androidプラグインなしのライブラリモジュールで十分です。数十のモジュールがある大規模プロジェクトでは、各モジュールのRobolectricテストが並行して実行され、エミュレーターでの逐次実行と比較してさらなる速度向上が得られます。
リソースの問題は、build.gradleにunitTests.includeAndroidResources = trueがない場合、またはマニフェストへの正しいパスを持つ@Configアノテーションがない場合に発生します。Robolectricはbuild/intermediatesからコンパイルされたリソースを使用します。
RobolectricテストはAndroid Studioで通常のJava/Kotlinテストと同様にデバッグできます。ブレークポイント、ステップスルーデバッグ、シャドウオブジェクトとその状態の検査が利用可能です。ロギングはVMオプションで-Drobolectric.logging=debugを設定することで有効になります。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。