android.app.Applicationというクラスを継承したカスタムApplicationを作成すれば、どのActivityからでも共通して利用できるオブジェクトが作成できます。便利なので扱いには注意は必要ですが、テストを行う際は、ActivityのonCreateが実行される前に差し替え可能なので、オリジナルのMockで差し替えたい場合などにも有効です。この辺りどうテストをやるのが良いのか、まだまだ勉強不足ですが......以下に差し替え方を掲載します。
クラスファイルは以下のような内容で追加します。
onCreateはアプリ起動時に呼ばれるメソッドです。loadはオリジナルのメソッドです。このカスタムApplicationをActivityで利用するには、以下のようにキャストして使います。
これを単に起動すると、以下のような順番で出力されます。
まず、CustomApplicationクラスに変って差し替えるクラスを作ります。
ActivityUnitTestCaseを継承したクラスで差し替えます。
このテストを実行すると、以下のような順番でログが出力されます。
いずれにせよ、CustomApplicationのonCreateは最初に呼ばれます。
この場合は、上記のような要領で差し替えコード(setUp()の部分)を記述してやれば良いでしょう。そして、MockMyApp.classの部分をCustomApplication.classと置き換えてやれば良いでしょう。
関連:JUnitから起動したService上でのApplicationのClassCastException
まず、カスタム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
コメント
コメントを投稿