Android Studio でテストコードを実行する方法をまとめておく。

  • Android Studio 1.3 が対象。

準備

古い解説サイトを見ると build.gradle の変更が必要と書いてあるが 1.3 では不要。
プロジェクト生成時に src/androidTest フォルダが作成されていてすぐにテストコードが書けるようになっている。

メニューの Run > Edit Configrations を選択して Android Tests を追加すれば準備完了。

テスト実行環境設定で変更する項目は3つ

  • テストの名前
  • Module は通常 App
  • デバイスは選択にしといたほうがよさげ

テストコード

これは Eclipse と変わらない。

単純な Activity テストのサンプル

package org.kotemaru.test1;

import android.test.ActivityUnitTestCase;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

public class MainActivityTest extends ActivityUnitTestCase<MainActivity> {

    public MainActivityTest(Class<MainActivity> activityClass) {
        super(activityClass);
    }

    // ボタンクリックのテスト
    public void test_onTestClick() throws Exception {
        Log.v("test", "test_onTestClick");
        assertEquals("Hello world!", getText(R.id.textView));
        click(R.id.testButton);
        assertEquals("Test message!", getText(R.id.textView));
    }

    //-----------------------------------------------------------------
    // Util
    private void click(int rid) {
        final View view = getActivity().findViewById(rid);
        getInstrumentation().runOnMainSync(new Runnable() {
            @Override
            public void run() {
                view.performClick();
            }
        });
    }

    private CharSequence getText(int rid) {
        return ((TextView) getActivity().findViewById(rid)).getText();
    }
}

複数の Activity 遷移のサンプル

package org.kotemaru.test1;

import android.app.Activity;
import android.app.Instrumentation;
import android.content.Intent;
import android.test.ActivityTestCase;
import android.test.ActivityUnitTestCase;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;

public class MultiActivityTest extends ActivityTestCase {
    @Override
    protected void setUp() throws Exception {
        super.setUp();
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setClassName("org.kotemaru.test1", MainActivity.class.getName());
        Activity act = getInstrumentation().startActivitySync(intent);
        setActivity(act);
    }

    /**
     * Main->Sub->Main の Activity 遷移のテスト
     */
    public void test_onSubActivityClick() throws Exception {
        Log.v("test", "test_onSubActivityClick");
        Instrumentation instrumentation = getInstrumentation();
        Instrumentation.ActivityMonitor monitor =
                instrumentation.addMonitor(SubActivity.class.getCanonicalName(), null, false);

        click(R.id.subActivityButton);
        Activity act = instrumentation.waitForMonitorWithTimeout(monitor, 10000);
        assertEquals(SubActivity.class, act.getClass());

        monitor = instrumentation.addMonitor(MainActivity.class.getCanonicalName(), null, false);
        Thread.sleep(1000); // TODO: wait activity resumed
        sendKeys(KeyEvent.KEYCODE_BACK);

        act = instrumentation.waitForMonitorWithTimeout(monitor, 10000);
        assertEquals(MainActivity.class, act.getClass());
    }

    //-----------------------------------------------------------------
    // Util
    private void click(int rid) {
        final View view = getActivity().findViewById(rid);
        getInstrumentation().runOnMainSync(new Runnable() {
            @Override
            public void run() {
                view.performClick();
            }
        });
    }

    private CharSequence getText(int rid) {
        return ((TextView) getActivity().findViewById(rid)).getText();
    }
}

実行

実行の種類を test に変更して実行するだけ。

デバイスの選択画面がでるのでエミュレータか実機を選択。

エミュレータで自動でテストが進む。

失敗するとスタックトレースがでるので当該の assert に飛ぶことができる。

まとめ

余計な手間がなく目的のテストコードだけ書けば良いようになっている。

操作系のユーティリティが必要だなと思ったら robotium というのが既にあるらしい。

問題は UI の仕様変更は頻繁なのでテストが追従できないことなんだよねー。