つくるの大好き。

つくるのが大好きな人の記録。

Android C++開発 [2] : InstrumentedTestでUIを表示する

InstrumentedTestを使えばデバイス上でUnitTestができますが、状態や映像を表示したりするにはUIが表示できると便利です。

InstrumentedTestにActivity表示のルールを追加する

Activityのテストをするにはテストクラスに ActivityTestRule というルールを追加します。
つまりテスト実行時にこのActivityを表示するように、といったルールの定義です。

ExampleInstrumentedTest.java

    @Rule
    public ActivityTestRule rule = new ActivityTestRule<>(MainActivity.class, true, true);

この記述を行うとビルドエラーが発生します。
なぜならInstrumentedTest実行時にこのクラスを参照する設定がされていないからです。
build.gradle の dependencies 内、 androidTestImplementation の部分に参照を追加するとビルドエラーは解消します。

build.gradle

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:rules:0.4'  #コレを追加
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

ActivityにUI要素を追加

実施するテストに応じてActivityに必要なUI要素を追加します。
ここでは文字列を表示する TextView を "textMessage" という名前で追加しました。

f:id:peugeot-106-s16:20181107153712p:plain

テストクラスからUI要素にアクセスする

テストクラスからActivity内のUI要素にアクセスするには、先ほど追加したActivityTestRule からActivityを取得し操作します。
ただUI要素はUIスレッドから操作する必要があるので直接操作することはできず、runOnUiThread()メソッドにアクションを渡し、非同期で実行させる必要があるのですこし面倒でした。 このようなユーティリティメソッドを作成しました。

    private void showMessageOnUiThread(String message)
    {
        class ShowTextAction implements Runnable
        {
            private String message;
            public ShowTextAction(String message)
            {
                this.message = message;
            }

            @Override
            public void run() {
                TextView messageText = rule.getActivity().findViewById(R.id.textMessage);
                messageText.setText(this.message);
            }
        }

        this.rule.getActivity().runOnUiThread(new ShowTextAction(message));
    }

テストメソッドからの呼び出し

以上の準備を行えばテストメソッド内から画面に文字列を表示することができます。
応用すれば様々な操作を行うことができます。それだけではなくこのRuleの真価はUIの自動テストが行えるところにあります。
ボタンをプッシュするといった人が行うようなアクションもシミュレートさせることができます。
さて、テストメソッドでC++から取得した文字列を表示するためにはこのような実装を行いました。

ExampleInstrumentedTest.java

    @Test
    public void stringFromJNITest() throws InterruptedException {
        String message = stringFromJNI();
        this.showMessageOnUiThread(message);

        Thread.sleep(5000);

        assertEquals("Hello from C++ to InstrumentedTest", message);
    }

実行結果はこのようになります。
C++から取得したメッセージが表示されています。

f:id:peugeot-106-s16:20181107154710j:plain

まとめ

Andoid実機で動作するInstrumentedTestで画面を表示し、UI要素にアクセスする方法をお伝えしました。

プロジェクト一式は下記にアップしています。

github.com