スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

AsyncTaskをJUnitでテストする方法

明けましておめでとうございます。
久しぶりに更新します。

今回はAndroidのAsyncTaskをJUnitでテストする方法を紹介します。

AsynkTaskはUIThreadでないと動作しません。またバックグランド処理が
完了した後にコールバックされるonPostExecute(Result)は、普通にテストケースを
実装してしまうとテストケースのスレッドではonPostExecute(Result)の実行をまってくれず
処理が終了してしまいます。
このような理由でテストケースを実装するにはコードにひと工夫が必要です。
以下がそのソースコードとなります。

1.まずはAsynkTaskの実装から(かなり適当)
-----
public class TestableAsyncTask extends AsyncTask {

    private Activity activity;
    private TextView textView;
    
    public TestableAsyncTask(Activity activity) {
        this.activity = activity;
    }
    
    @Override
    protected String doInBackground(String... args) {
        return args[0];
    }

    /* (non-Javadoc)
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    @Override
    protected void onPostExecute(String result) {
        textView.setText("AsynkTask Executed Count:" + result);
    }

    /* (non-Javadoc)
     * @see android.os.AsyncTask#onPreExecute()
     */
    @Override
    protected void onPreExecute() {
        textView = (TextView)activity.findViewById(R.id.txtview);
    }

}
-----
わざわざ非同期にする必要がないような処理ですが気にせず(;^_^A
ちなみにonPreExecute()はdoInBackground()の前に実行されるコールバックでUIThreadで動作します。

2.テストケースのサンプル
-----
public class TestableAsyncTaskTestCase extends ActivityInstrumentationTestCase2<AsyncTaskSampleActivity>
 :
    public void testTestableAsyncTask() throws Throwable {
        // create CountDownLatch.
        final CountDownLatch signal = new CountDownLatch(1);
        
        // create subclass of test target asynctask.
        final AsyncTask testTask
            = new TestableAsyncTask(mActivity) {

                /* (non-Javadoc)
                 * @see com.makochi.asynctasksample.logic.TestableAsyncTask#onPostExecute(java.lang.String)
                 */
                @Override
                protected void onPostExecute(String result) {
                    super.onPostExecute(result);
                    
                    // unlock testcase's thread.
                    signal.countDown();
                }
            
        };
        
        // execute asynctask.
        runTestOnUiThread(new Runnable() {
            
            @Override
            public void run() {
                testTask.execute("1");
            }
        });
        
        // wait for asynctask.
        signal.await(30, TimeUnit.SECONDS);
        
        assertEquals("TextViewのText", "AsynkTask Executed Count:1", mTextView.getText());
    }
}
-----
テストケースは「ActivityInstrumentationTestCase2」のサブクラスで実装しています。
このクラスはテストケースでアクティビティを使いたい場合は、UIThreadでテストメソッド内の
処理を実行させたい場合に利用します(詳しい実装方法はandroid deveopers参照)

そして今回のポイントは赤色で示したところです。

まず、AsyncTaskのコールバックの実行を待機するために「java.util.concurrent.CountDownLatch」の
インスタンスを生成します。
このクラスは他のスレッドで実行されている処理を待機する為のクラスで生成する時のコンストラクタ
で指定した回数分だけcountDown()メソッドが呼ばれるまで、await()メソッドを呼び出した箇所で待機します。
今回はAsyncTaskのバックグランド処理の完了であるonPostExecute()メソッドが呼び出されるまで待機します。

続いてテストをしたいAsyncTaskのサブクラスを実装します。
その際、onPostExecute()メソッドをオーバライドして、super.onPostExecute()を呼び出した後に
CountDownLatchのcountDown()メソッドを呼び出します。
(具象クラスも生成と同時にメソッドオーバライド可能なんですね)
ここでcountDown()メソッドを呼びことにより、テストケースのスレッド待機が解除されます。
(今回はCountDownLatchの生成時に1を指定している為、countDown()も1回でスレッドブロックが解除)

次のコードは実際にAsyncTaskを実行する部分です。
runTestOnUiThread()メソッドの中でAsyncTaskを実行します。

最後がawait()メソッドでAsyncTaskの実行完了を待機します。
第一引数に指定した30秒経過するか、指定回数countDown()メソッドが呼び出されるまで
このテストケースのスレッドはこの箇所で待機します。

以上です。


■参考
・android developers - Hello, Testing
http://developer.android.com/resources/tutorials/testing/helloandroid_test.html

・android developers - ActivityInstrumentationTestCase2
http://developer.android.com/reference/android/test/ActivityInstrumentationTestCase2.html

・JSE6 API Reference - CountDownLatch
http://java.sun.com/javase/ja/6/docs/ja/api/java/util/concurrent/CountDownLatch.html
スポンサーサイト
プロフィール

まこち

Author:まこち
スマートフォンのアプリ開発やWebサイト構築等を仕事や趣味でやっています。
最近はグラフデータベースも始めました。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QR
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。