みんからきりまで

きりみんです。

Espressoがsupport libraryになってAndroidでJUnit4が使えるようになったと聞いたので試してみた

参考
Espresso 2.0 が Android support library の一部としてリリースされた - ひだまりソケットは壊れない

Espressoがsupport libraryに入り、ついでにJUnit4を含むAndroidの標準自動テストを便利にするクラスが色々と追加されたようです。
ということで、Androidプロジェクトでのテストをおさらいしながら導入してみました。

といっても
EspressoSetupInstructions - android-test-kit - Setup instructions for Espresso v2.0 - Google's Testing Tools For Android - Google Project Hosting
を見ながら
googlesamples/android-testing · GitHub
の通りに真似して設定しただけですが。

build.gradleのdependenciesに関連するライブラリを設定する

とりあえずsupportに登録されたEspressoなどのテスト関連物をdependenciesに書きます。

compile 'com.android.support:support-annotations:21.0.3'

androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
androidTestCompile 'com.android.support.test:testing-support-lib:0.1'

testInstrumentationRunnerを設定する

同じくbuild.gradleのdefaultConfigのtestInstrumentationRunnerにandroid.support.test.runner.AndroidJUnitRunnerを設定します。

defaultConfig {
    testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

テストクラス用パッケージを作成する

最近Android Studioで生成したプロジェクトであればデフォルトでテストクラス用のテストパッケージが作成されているかもしれませんが、もしまだ無ければ作成する必要があるようです。
appモジュールのsrcディレクトリ直下にmainと並ぶようにandroidTest/java/ディレクトリを作成し、その中にapplicationId(アプリのパッケージ名)のディレクトリを作成します。

テストクラスを作成する

テストはこんな感じで普通にJUnit4で書けます。
もうメソッド名の先頭にtestを付けなくてもいいんですね。

import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.is;

@RunWith(AndroidJUnit4.class)
public class SampleTest {

    @Test
    public void sample(){
        assertThat(1 + 1, is(2));
    }
}

 
どうやらInstrumentationRegistryというクラスを使うとContextが取得出来るようです。

@RunWith(AndroidJUnit4.class)
public class SampleTest {

    @Test
    public void sample() {
        TextView textView = new TextView(InstrumentationRegistry.getContext());
        textView.setText("test");
        assertThat(textView.getText().toString(), is("test"));
    }
}

 
Espressoを使ったUIテストはこんな感じだと思います。僕はRobotiumしか使ったことがないのであんまり詳しくは知りません。

@RunWith(AndroidJUnit4.class)
public class SettingMainActivityTest extends ActivityInstrumentationTestCase2<SettingMainActivity> {

    private SettingMainActivity activity;

    public SettingMainActivityTest() {
        super(SettingMainActivity.class);
    }

    @Before
    public void setUp() throws Exception {
        super.setUp();
        injectInstrumentation(InstrumentationRegistry.getInstrumentation());
        activity = getActivity();
    }

    @After
    public void tearDown() throws Exception {
        super.tearDown();
    }

    @Test
    public void checkStartButtonText() {
        onView(withId(R.id.settingStartButtonTextView)).check(matches(withText("Start")));
    }
}

configurationを作成する

テストを実行するためのconfigurationを作成します。
普通にAndroid Testsを選択し、specific instrumentation runnerのところにandroid.support.test.runner.AndroidJUnitRunnerと入力すればOKです。

追加したconfigurationを実行すれば実機もしくはエミュレータ上でテストが走るはずです。

エラーが出た

どうもLICENSE.txtが重複しているというビルドエラーが出てしまうようです。 エラーメッセージに従いbuild.gradleに

packagingOptions {
    exclude 'LICENSE.txt'
}

と記述すればとりあえずは大丈夫なようです。

雑感

AndroidでのテストはUIテストならRobotium、単体テストはRoborectricを使ったりしますが、Espressoがsupport libraryに入ったからにはEspressoを使ってゆくのが幸せに近いのでしょうか。
単体テストに関しては、自分の環境ではRoborectricを使わなくてもUIテストを走らせなければGenyMotion上で一瞬(1秒以下)で実行する事が出来るようなので、もはや環境構築が容易な標準の仕組みだけで十分テスト駆動開発が出来るレベルになったんじゃないかなーという気がしています。

といっても、今のところ僕は全然テストが書けていない状態なので、これを機にJunit実践入門を読み直してテストをどんどん書いていきたいですね。