みんな大好き単体テストライブラリ。
JVM上でテストを素早く実行できて便利!だけど、落とし穴も色々ある・・・
テストを書いていてハマったポイントを紹介します。
公式ドキュメントにはかなり基本的なことしか書いてない。
サンプルプロジェクトにサンプルコードがほとんどない
最も頼りになるドキュメントは、本家プロジェクトのテストコード
例:RobolectricTestRunnerのテストコード
後はRobolectric本体のコードを読んで理解する。
動機はサーバからのレスポンスなどのテストデータを別ファイルにして/src/test/assetsに置くため。
一方で/src/main/assetsも読み込める状態を維持したい。
対応方法
問題点
例:Build.VERSION.RELEASE(OSのバージョン番号)の値を書き換えたい。
が、宣言時に初期化されている。かつstatic finalなので書き換えられない。
public static final String RELEASE = getString("ro.build.version.release");
private static String getString(String property) {
return SystemProperties.get(property, UNKNOWN);
}
そもそもMVCのControllerは色んなクラスに依存していることが多いのでテストはやりづらい。
Fragmentのテストコード例:
// 事前処理
OrderListFragment target = OrderListFragment_.builder().build();
Robolectric.addPendingHttpResponse(200, TestUtils.getStringFromAssets(TestDataType.HTTP, "orderList.response.json"));
// 処理実行
startFragment(target, MockMyActivity.class);
Robolectric.runBackgroundTasks();
Robolectric.runUiThreadTasks();
// 検証
List<Order> orders = (List<Order>) Whitebox.getInternalState(target, "orders");
assertThat(orders.size()).isEqualTo(6);
FragmentからActivityへのcallbackをインターフェース経由でやっていればActivityのMockは作りやすい。
ActivityのMockの例:
public class MockMyActivity extends FragmentActivity implements IErrorHandler {
@Override
public void onError(final Exception e) {
Log.d("MockMyActivity", "onError", e);
}
}
Robolectricと同じアプローチに見える。(JVMで実行、Android SDKのクラスはMockに置き換え)
Shadowがまだないので現状使えない。が、いずれRobolectricを置き換えるようになり、テストコードの書き直しが必要になるかも。。
一旦様子見で。