AndroidのJUnitTestではAsyncTaskのexecuteメソッドの呼び出し時点で終了してしまうので、ちょっとした技が必要。
手段(1)
・内部ロジックを全てメソッドに書き出し、privateメソッドのテスト方法を用いてテスト
→処理の単体テストには有効だが、onPreExecute~onPostExecuteの流れを含めてテストしたい場合にはできない
単体テストという意味では、(1)でも十分だが、Activityのテストを行っているとonPostExecuteからのキックを確認したい場合などが多くあるので、不十分。
手段(2)
・Taskが終わるのを待たせるようにする
ということで、(2)の実装例。
テストしたいAsyncのクラス
SampleTask.java
public class SampleTask extends AsyncTask<String, Integer, Integer> {
EventListener listener = null;
Context context =null;
public interface EventListener{
public void onFinish(int result);
}
public SampleTask(Context context, EventListener listener) {
this.listener =listener;
this.context = context;
}
@Override
protected Integer doInBackground(String... uID) {
// なんか処理
return 0;
}
@Override
protected void onPostExecute(Integer result) {
if(listener!=null){
listener.onFinish(result);
}
}
}
テスト呼び出しコード
TestTask.java
public class TestTask extends ActivityInstrumentationTestCase2<MainActivity>{
Activity mActivity = null;
EventListener mListener = null;
public TestTask(){
super(MainActivity.class);
}
protected void setUp() throws Exception {
super.setUp();
// アクティビティを取得
mActivity = getActivity();
}
protected void tearDown() throws Exception {
super.tearDown();
}
/**
タスクを起動する
*/
private void taskExecute(EventListener l) throws Throwable {
// create CountDownLatch.
final CountDownLatch signal = new CountDownLatch(1);
mListener = l;
runTestOnUiThread(new Runnable() {
public void run() {
try {
SampleTask task = new SampleTask (mActivity, new EventListener() {
public void onFinish(int result) {
if(mListener!=null){
mListener.onFinish(result);
}
signal.countDown(); // release
}
});
task.execute("nickname");
} catch (Exception e) {
Log.e(TAG, "ERROR", e);
fail();
}
}
});
try {
signal.await();// wait for callback
} catch (InterruptedException e1) {
fail();
e1.printStackTrace();
}
}
/** テストコード */
public void test000() throws Throwable{
// 前提処理かなにか
// タスク呼び出し
taskExecute(new EventListener() {
public void onFinish(int result) {
// ここに検証コードを書く
assertTrue(0==result);
}
});
}
}
参考:http://stackoverflow.com/questions/9774792/asynctask-onpostexecute-not-called-in-unit-test-case
上記参考頁との違いは、タスク呼び出し部分をメソッド化TestTask#taskExecute
してあるところだけです。
SampleTask部分をテンプレートクラス化すれば、「AsyncTaskのJUnitTestを行うテストクラスの基本となる抽象クラス」が出来るかな。
気が向いたら追記します(笑)