Android、Java、Web系、Linux、マラソン等の備忘録

2014/01/05

AndroidのカスタムApplicationをテストで差し替える

0 件のコメント
android.app.Applicationというクラスを継承したカスタムApplicationを作成すれば、どのActivityからでも共通して利用できるオブジェクトが作成できます。便利なので扱いには注意は必要ですが、テストを行う際は、ActivityのonCreateが実行される前に差し替え可能なので、オリジナルのMockで差し替えたい場合などにも有効です。この辺りどうテストをやるのが良いのか、まだまだ勉強不足ですが......以下に差し替え方を掲載します。

まず、カスタムApplicationの作り方

AndroidManifest.xmlのapplicationタグ内にandroid:nameの欄にカスタムApplicationを定義します。とりあえずクラス名はCustomApplicationとします。

<application
    android:name="net.takaiwa.CustomApplication"
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="net.takaiwa.StartActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

クラスファイルは以下のような内容で追加します。
package net.takaiwa;

import android.app.Application;
import android.util.Log;

public class CustomApplication extends Application {

    private static final String TAG = "net.takaiwa";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.v(TAG, "Custom App onCreate");
    }

    public void load() {
        Log.v(TAG, "Custom App load");
    }
}

onCreateはアプリ起動時に呼ばれるメソッドです。loadはオリジナルのメソッドです。このカスタムApplicationをActivityで利用するには、以下のようにキャストして使います。

package net.takaiwa;

import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;

public class StartActivity extends Activity {

    private static final String TAG = "net.takaiwa";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_start);

        Log.v(TAG, "StartActivity onCreate");

        CustomApplication app = (CustomApplication)getApplication();
        app.load();
    }
}

これを単に起動すると、以下のような順番で出力されます。
Custom App onCreate
StartActivity onCreate
Custom App load

テストプロジェクトで差し替えて実行

StartActivityのapp.load()というのが実行される前に、CustomApplicationを差し替えて別のログを出力させてみたいと思います。

まず、CustomApplicationクラスに変って差し替えるクラスを作ります。

    public static class MockMyApp extends CustomApplication  {
        @Override
        public void load() {
            Log.v(TAG, "MockMyApp load");
        }
    }

ActivityUnitTestCaseを継承したクラスで差し替えます。

public class StartActivityTest extends ActivityUnitTestCase<StartActivity> {

    private static final String TAG = "net.takaiwa.test";

    public StartActivityTest() {
        super(StartActivity.class);
    }

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        Log.v(TAG, "StartActivityTest setUp");

        Context context = getInstrumentation().getTargetContext();

        Application app =
            Instrumentation.newApplication(MockMyApp.class, context);
        app.onCreate();
        setApplication(app);
    }

    public void test_ライフサイクルのテスト() {

        Log.v(TAG, "StartActivityTest test_ライフサイクルのテスト start");

        startActivity(new Intent(), null, null);

        Log.v(TAG, "StartActivityTest test_ライフサイクルのテスト end");

    }
}

このテストを実行すると、以下のような順番でログが出力されます。

Custom App onCreate
StartActivityTest setUp
Custom App onCreate
StartActivityTest test_ライフサイクルのテスト start
StartActivity onCreate
MockMyApp load
StartActivityTest test_ライフサイクルのテスト end

いずれにせよ、CustomApplicationのonCreateは最初に呼ばれます。

ちなみに

上記のような差し替える意図がない場合(上記のsetUp()の部分がない場合)、Activity上でCustomApplication app = (CustomApplication)getApplication();のようにキャストしてカスタムApplicationを取得するような実装をしていて、ActivityUnitTestCase等で実行すると、以下のようなExceptionが発生します。

java.lang.ClassCastException: android.test.mock.MockApplication cannot be cast to net.takaiwa.CustomApplication 

この場合は、上記のような要領で差し替えコード(setUp()の部分)を記述してやれば良いでしょう。そして、MockMyApp.classの部分をCustomApplication.classと置き換えてやれば良いでしょう。

関連:JUnitから起動したService上でのApplicationのClassCastException


0 件のコメント :

コメントを投稿