1. Qiita
  2. 投稿
  3. Espresso

Espresso 2.0とRobolectricを併用したテスト環境の作り方

  • 153
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

2015.6.9追記:Android Studio 1.2 + Robolectric 3の組み合わせが良さそうなので、この記事をあまり鵜呑みにしないでください(参考

Androiderの皆さん、テストしてますか?

今回は、UIテストが幸せになるEspresso 2.0と、ユニットテストが幸せになるRobolectricをAndroid Studio的に自然な形で併存させるための設定をご紹介します。

ゴールとしては、下記のような表示になります。

スクリーンショット 2015-02-03 17.27.05.png

Android Studioではあまり見かけないテストフォルダの配置に「おっ」と思った方は、次項を読み飛ばしてその先へどうぞ。

前提知識:これまでのテスト

Espresso

UIテストをモリモリ書いてきた諸兄は、Espressoと仲良くしていらっしゃることと思います。Support Libraryの一部としてEspresso 2.0が配布されるようになり、JUnit4が使えるようになったことを喜んだのは、記憶に新しいところです。

Robolectric

また、ユニットテストをモリモリ書いてきた諸兄は、Robolectricと仲良くしていらっしゃることと思います。JVM上で高速にテストを回すことができるRobolectricは、手元でのTDDにおいても、サーバー上のCIにおいても、欠かすことのできない存在になってきていますね。

問題点と解決策(旧)

どちらもDB層からUI層まで幅広い領域のテストに対応していますが、動作環境や実行速度の一長一短があるため、上手く使い分けができると幸せを享受しやすそうです。

しかし、両方を扱うには、少し問題がありました。Android Plugin for GradleやAndroid Studioは、テスト用ソースディレクトリを1つしか認識することができなかったのです。JUnit3しか書けなかった昔のandroidTestと、JUnit4でテストを書くRobolectricをプロジェクト内に併存させるのは、難しいものに思われました。

この問題への一案を提示したのが、robolectric/deckard-gradleというサンプルプロジェクトでした。

  • src/test/
    • com.example/
      • espresso/
        • FirstUITest
        • SecondUITest
      • FirstRobolectricTest
      • SecondRobolectricTest

deckard-gradleでは、上記のようなパッケージ構造にした後、次のような設定を記述することで、実行されるテストの振り分けを行っていました。

build.gradle
robolectric {
    include '**/*Test.class'
    exclude '**/espresso/**/*.class'
}

これらの設定により、下記のテストが可能になっていました。

  • ./gradlew connectedAndroidTest
  • ./gradlew test
  • Android Studio上でのandroidTestの実行

これはこれで良いものでしたが、少し不自然な対応だったために、1つの問題が残りました。

Espresso用のパッケージを別に用意したために、パッケージプライベートなフィールドに直接アクセスすることによる、テスト上の利便性を享受できなくなってしまったのです。

パッケージプライベートをテストで利用している例
@Test
public void 各Viewがインジェクトされている() {
    assertThat(activity.toolbar, is(not(nullValue())));
    assertThat(activity.tvDisplay, is(not(nullValue())));
    assertThat(activity.ivPicasso, is(not(nullValue())));
}

余談:その他の問題

他にも、旧来のdeckard-gradle方式による環境構築には、いくつかの問題がありました。

  • RobolectricテストをAndroid Studio上から実行することができない(通常のRobolectricの問題)
  • Espresso 2.0とRobolectricが混在した環境でAndroidJUnitRunnerを走らせると、Robolectricテストも実行しようとしてエラーになる

android-unit-test + Android Studio Unit Test

Espresso 2.0の時代に追従すべく、日本時間で2月3日の早朝に大きなリニューアルコミットがdeckard-gradleにマージされました

できるようになったこと

今回のリニューアルで、できるようになったことを列挙します。

  • src/androidTestに置いたEspresso 2.0方式のテストを./gradlew connectedAndroidTestで実行できるようになった
  • src/testに置いたRobolectricテストを./gradlew testで実行できるようになった
  • Android Studio上でのandroidTestの実行
  • 以下はAndroid Studio Unit Testプラグイン導入後に実行可能になる
    • Android Studio上でのRobolectricテストの実行ができるようになった
    • Android Studio上でsrc/androidTestsrc/testが両方ともテストソースディレクトリとして認識される(緑色のアイコンになる)

大きな変更点としては下記2点が挙げられます。

  • テストの種類ごとにディレクトリを分けても、それぞれにパスが通ったままテストコードを書けるようになった
  • Android Studio上でRobolectricテストを実行できるようになった

実装の要点

android-unit-testによるテスト環境構築について、要点だけ解説します。

Espresso 2.0特有の設定内容(AndroidJUnitRunnerとか)については特に説明しません。他の記事をご覧ください。

1. robolectric-gradle-pluginを置き換える

もうrobolectric-gradle-pluginは使いません。ありがとう。さようなら。

代わりに、android-unit-testプラグインを使います。

build.gradle
classpath 'com.github.jcandksolutions.gradle:android-unit-test:2.1.1'

これに伴い、apply plugin: 'robolectric'robolectric { ... }などのコードも削除します。これまでrobolectricブロックに書いていた設定を今後も扱いたい場合は、android-unit-testのREADMEに類似の情報がありますので、適宜設定してください。

2. プラグインの適用とテスト用のdependencyを記述する

まずはandroid-unit-testプラグインを有効にします。必ずandroid{ ... }ブロックの 下に 記述しましょう。

build.gradle
apply plugin: 'com.android.application'

android {
  ...
}

apply plugin: 'android-unit-test'

さらにその下には、テスト用のdependencyを記述できます。Espressoテスト向けはandroidTestCompileとして、Robolectricテスト向けはtestCompileとして記述します。

下記は、deckard-gradleのbuild.gradleにおける一例です。

build.gradle
apply plugin: 'android-unit-test'

dependencies {
    repositories {
        mavenCentral()
    }

    // Espresso
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.0')
    androidTestCompile('com.android.support.test:testing-support-lib:0.1')

    // Robolectric
    testCompile 'junit:junit:4.12'
    testCompile 'org.hamcrest:hamcrest-core:1.1'
    testCompile 'org.hamcrest:hamcrest-library:1.1'
    testCompile 'org.hamcrest:hamcrest-integration:1.1'

    testCompile('org.robolectric:robolectric:2.4') {
        exclude module: 'classworlds'
        exclude module: 'commons-logging'
        exclude module: 'httpclient'
        exclude module: 'maven-artifact'
        exclude module: 'maven-artifact-manager'
        exclude module: 'maven-error-diagnostics'
        exclude module: 'maven-model'
        exclude module: 'maven-project'
        exclude module: 'maven-settings'
        exclude module: 'plexus-container-default'
        exclude module: 'plexus-interpolation'
        exclude module: 'plexus-utils'
        exclude module: 'wagon-file'
        exclude module: 'wagon-http-lightweight'
        exclude module: 'wagon-provider-api'
    }
}

テスト内でmockitoなどを使いたい場合には、このタイミングで記述しておきましょう。

ひとまずこの段階で、./gradlew connectedAndroidTest./gradlew testは実行できるようになっているはずです。お手軽ですね。

3. Android Studioにプラグインを入れる

Preferences > Plugins > Browse RepositoriesAndroid Studio Unit Test を探してインストールします。

スクリーンショット 2015-02-04 2.00.17.png

これで準備は完了です。

Robolectricで使用していた android.sourceSets.androidTest.setRoot("src/test") が残っていると、上手くいかないので事前にbuild.gradleから削除しておきましょう。

src/androidTestsrc/testが両方ともテストソースディレクトリとして扱われていることを確認できるはずです。

スクリーンショット 2015-02-03 17.27.05.png

Robolectricテストを動かしてみる

それでは、RobolectricのテストをAndroid Studioから実行してみましょう。どれかのテストクラスを右クリックして、JUnitテストとして実行します。(ドロイド君ではない方です)

スクリーンショット 2015-02-04 2.10.55.png

すると、Android Studioのテスト結果画面が現れます。やはり、テストの成功が緑色のバーで見れると、達成感がありますね。

スクリーンショット 2015-02-04 2.15.08.png

まとめ

android-unit-testプラグインを使うことで、Android標準のテスティングフレームワークとRobolectricを、Android Studio内で編集・実行しやすい形で共存させることができるようになりました。

UIテストに強いEspressoと、ユニットテストに強いRobolectricを上手く使い分けながら、堅牢なアプリを開発するべく、ゴリゴリとテストを書いていけたら素晴らしいですね。

それでは皆様、良いテストライフを。

宣伝

ウォーターセル株式会社では、農業界に新しい情報プラットフォームを構築し、生産者に嬉しい情報の扱い方を模索しようとしています。この難題を一緒に考えてくれるAndroidアプリエンジニア、iOSアプリエンジニア、インフラエンジニア、Webフロントエンドエンジニア、Railsエンジニアを探しています。

興味のある方はTwitterで@Nkznへ空リプか何かください。

Comments Loading...