スキップしてメイン コンテンツに移動

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

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


コメント

このブログの人気の投稿

Javaでprivateなfieldやmethodにアクセスする

JUnitでテストしてると、privateなフィールドにアクセスして、値を参照したりセットしたりしたくなるわけですが、よく使うのでメモしておきます。 例えば、次のような対象のクラスがあるとします。 public class ParentClass { private String hoge = "ParentClass!!"; public void dispMsg() { System.out.println("dispMsg:" + hoge); } private void privateDispMsg(String msg) { System.out.println("dispMsg:" + msg); } }

GolangでWindows GUIアプリケーション

GUIアプリ作成の前提 社内ツールとしてexeで配布 開発環境はGoLandを使う 社内ツールとしてexeを配布ということであれば、Visual StudioでC#による開発だと思います。しかしながら、Go言語を習得したいのと、GoLandの補完機能が便利で、Android Studio使っていたこともあり、とっつきやすいという点からGo縛りでGUIアプリケーションを考えたいと思います。 lxn/walk Windows application library kit for Go. Windows向けしか考えていないので、まずこのライブラリなのですが、ボタンやコンボボックスが思ったように並ばなかったり、手軽にイメージボタンを配置したりなど、簡単にレイアウトを変更できない課題に直面しました。レイアウト作成だけで時間を取られてしまいます。そう言えば、Androidアプリ開発のときは、XMLでデザイン部分を切り離してたのを思い出して、今回の調査の運びとなりました。 fyne-io/fyne Cross platform native GUIs designed for Go based on Material Design. Supports: Linux, macOS, Windows, BSD, iOS and Android. walkと比べると、クロスプラットフォームで作成できるのですが、こちらもコードの中にデザインを書いていく形でした。 therecipe/qt therecipe/qt allows you to write Qt applications entirely in Go or JavaScript. Qt Creatorなるものがあるようで、デザイン部分を切り離せる印象はあるものの、最新のPCでもビルドに時間がかかるようで、学習コストもかかるという記事を見かけて断念しました。 どうしたものかとツイートしましたら、下記のようにご助言をいただいた。 同じ課題に対し色々試した結果、PWAのフルキャッシュドに落ち着いた。中身はGo+WASMで。 https://t.co/e60whDTV16 — のぼのぼ📡 (@nobonobo) July 21, 2020 PWA 早速調べてみました。Googleが進めているプロジェクトで、ネイティブアプリのよ

Eclipseの高速化メモ

Eclipseが重いと一言に言っても、いろいろな工程での話があると思いますが、過去記事のなども含めてこの記事にピックアップしておきたいと思います。以下はWindows環境での話です。