ボクココ

個人開発に関するテックブログ

RoboGuiceテストの仕方の翻訳をしてみた

https://code.google.com/p/roboguice/wiki/Testing
こちらを勉強を兼ねて翻訳します。

Testing

RoboGuiceアプリのテストの仕方

始める前に

ユニットテストをするための完全な説明はこのドキュメントの範囲を超えるが、これはより多くの共通のミスを防ぐのを助ける価値がある。

まず始めに、テストプロジェクトを作ろう。このプロジェクトはあなたのメインアプリのプロジェクトに明確に依存させておく必要がある。roboguice かguiceに依存を持つべきではない
次にそれを利用するどんなライブラリもエクスポートするためにメインアプリプロジェクトを修正しよう。特に、roboguice and guice librariesがエクスポートしていることを忘れずに!

最後にテストプロジェクトのAndroidManifest.xmlに以下の and スニペットがあることを確認しよう。






RoboUnitTestCaseでユニットテスト

ユニットテストはテストの種類において最も直接的で、それらの単純なユニットテストはRoboUnitTestCase で使える。-それはResourceやActivity,ContentProvider、Service、Applicationなどの依存を持っていない。

RoboUnitTestCase はランダムなビットコードやユーティリティクラス、ドメインモデルなどをテストするのによい。以下は一例だ。


public class MyTest extends RoboUnitTestCase {

// @*Test アノテーションを置くのをわすれずに。そして
// テストケース名の先頭が"test"で始めるのにも注意。
@MediumTest
public void test01() {
// Make sure you're using com.mydomain.R, not com.mydomain.test.R
assertEquals("Hello World, Lop!", getContext().getString(com.mydomain.R.string.hello));
}

}

もしInstrumentationTestCaseを知っているのなら、RoboUnitTestCase はあなたのApplicationで指定した設定を元にしたGuice インジェクションを追加しただけだ。
※テストを動かすための注意として、以下のようなApplicationクラスのコンストラクタを追加する必要がある。

public MyApplication( Instrumentation instrumentation ) {
super();
attachBaseContext(instrumentation.getTargetContext());
}

RoboActivityUnitTestCaseを用いたユニットテスト

RoboUnitTestCase のユニットテストは単純だったが、あなたのユーティリティクラスはもっとアクティビティに対するユニットテストが必要であるとわかるだろう。アクティビティのユニットテストはRoboActivityUnitTestCaseでほとんどが可能だ。
アクティビティの新規インスタンスはRoboActivityUnitTestCaseにあるそれぞれのテストメソッドで作成される。そのため、アクティビティのたくさんのテストを孤立させるのにとても良い手段である。詳細は ActivityUnitTestCaseまで。
下記のコードがそのサンプルコードである。


public class MyActivityUnitTest extends RoboActivityUnitTestCase {

protected Intent intent = new Intent(Intent.ACTION_MAIN);

public MyActivityTest() {
super(MyActivity.class);
}


// @*Test アノテーションを置くのをわすれずに。そして
// テストケース名の先頭が"test"で始めるのにも注意。
@MediumTest
public void test01() {
setApplication( new MyApplication( getInstrumentation().getTargetContext() ) );
final Activity activity = startActivity(intent, null, null);

// 何らかのテスト
assertNotNull(activity);
assertEquals( *1.getText(), "Hello World, Lop!");
}
}

RoboUnitTestCaseの場合は、あなたのApplicationクラスに下記のコンストラクタを追加する必要がある。

public MyApplication( Context context ) {
super();
attachBaseContext(context);
}

ActivityInstrumentationTestCase2での機能テスト

ActivityUnitTestCase2 はアプリが端から端まで全ての実行をしたい場合に使われるべきである。そのテストはアプリと実行環境をすべて実行し、それぞれに境界がない。Seleniumテストに近い: テストとしてユーザストーリーを実装し、スクリーン上で実際に実行する。ActivityUnitTestCase、それはアクティビティがスクリーン上に表示されないものだが、それはは動かない。そしてコンテキストを他のアクティビティに切り替えることは禁止されている。
・ActivityUnitTestCase はアクティビティのユニットテストを切り離す。(早いけど制限有)
・ActivityInstrTestCase2 はフルの端から端までのテスト(制限なし)


public class MyActivityFunctionalTest extends ActivityInstrumentationTestCase2 {

public MyActivityFunctionalTest() {
super("com.mydomain",MyActivity.class);
}


// @*Test アノテーションを置くのをわすれずに。そして
// テストケース名の先頭が"test"で始めるのにも注意。
@MediumTest
public void test01() {
final Activity activity = getActivity();

// 何らかのテスト
assertNotNull(activity);
assertEquals( *2.getText(), "Hello World, Lop!");
}
}

よくある落とし穴

バックグラウンドタスクのテスト

もしあなたがバックグラウンドスレッドを利用しているなら、バックグラウンドスレッドが終わった後にメインのUIスレッドの更新を実行しなければならくなるだろう。このパターンのクラスのとしてはAsyncTask, UserTaskや Handlerなどがある.
普通はバックグラウンドが発生するテストケースを作って、そのバックグラウンドの実行結果が終わったことをメインスレッドがチェックするようにするだろう。しかしながら、これはいくつかのケースで動かない場合がある。
問題は、AsyncTaskなどの関連は、バックグラウンドで実行し、それらが終わった後にメインのUIスレッドのアクションを投げることにある(例えばViewを更新するためなど)。この特定のケースではメインUIスレッドはテストスレッドをブロックするが、それはAsyncTaskがonPostExecute()メソッドを実行するまで永遠に待つことを意味する。
これは、新しいスレッドを作って、偽のUIスレッドをLooper.prepare()を呼ぶことで作りだし、Looper.loop()によって得ることができる。 RoboLooperThreadはこれをあなたのために管理してくれる。


public class MyBackgroundTaskTest extends RoboUnitTestCase {

@MediumTest
public void test01() throws InterruptedException {
// java finalであることを必要とする。
final String[] result = {null};
final CountDownLatch latch = new CountDownLatch(1);

// このスレッドは偽のUIスレッドである。
new RoboLooperThread() {
public void run() {

new MyBackgroundTask() {

@Override
protected void onPostExecute(String s) {
result[0] = s;
}

@Override
protected void onFinally() {
latch.countDown();
}

}.execute();

}
}.start();

latch.await();
assertTrue(result[0], result[0].contains("Search"));
}
}

バックグラウンドスレッドなしでバックグラウンドタスクのテストをする

Asynctaskを使っているなら、フォアグラウンドスレッドを全体的に実行することによって全てのバックグラウンドタスクをスキップできる。


public class MyBackgroundTaskTest extends RoboUnitTestCase {

@MediumTest
public void test01() throws InterruptedException {
final String result = new MyAsyncTask().get();
assertTrue(result.contains("Search"));
}
}
注意:AsyncTaskがonPostExecuteの実行を必要としないコードなら、適切に実行されないから、このテクニックはdoInBackgroundの結果をテストするためだけに有効である。
不幸にもまだSafeAsyncTask に相当する簡単なものはない。

AndroidUnitTestCase は動作しない

AndroidUnitTestCase の利用をオススメしない。なぜならテストされるアプリのContextや Resourceのアクセスを許可しないからだ。これはいくつかのテストなら問題ないが、他のケースで難しさや混乱を生む原因となる。AndroidUnitTestCaseを利用する利点があんまないので、代わりに(InstrumentationTestCase の代わりにベースとなっている)RoboUnitTestCase を使うことを提案する。

*1:TextView)activity.findViewById(R.id.hello

*2:TextView)activity.findViewById(R.id.hello