Android UIテストフレームワークのひとつEspressoは今年の1月からずーっとコミットがなさそうで、これはもうお亡くなりになったのか。。。と思っていたら突如2.0が発表されました。
ReleaseNotes
Android Developers
ということで早速試してみたのでメモ。
(細かい所までは見れてないです)
そもそもEspressoとは?
上記に記載したようにGoogleが2013年に発表したUIテストフレームワークのひとつです。
AndroidのUIテストフレームワークはrobotiumやuiautomatorなんかがありますね。
calabash-androidというのもあります。
その中でEspressoの特徴ですが、とにかく実行速度がめちゃめちゃ早いことだと思います。
robotiumとの実行速度比較は以下のスライドで見れます。
UI Testing On Android(スライド17)
作成するアプリの画面が少なければ問題ないかもしれませんが、そうでない場合に相当数のUIテストが必要で、そのUIテストに何時間も掛かるようでは継続的インテグレーションへの導入も難しいと思います。そういった意味でEspressoはとても魅力的なテストフレームワークの一つではないかと思います。
Espresso2.0で何が変わった?
詳細はリリースノートを見ていただくとして以下が気になった変更点です。
- Android Support Repositoryの一部になった
- Espressoのドキュメントは2015年の早いタイミングでAndorid Developersへ移動する
- テストランナーがGoogleInstrumentationTestRunneからAndroidJUnitRunnerになった。また、AndroidJUnitRunnerはJUnit4を含むのでJUnit4のスタイルでも記述できる
- Lollipop対応
- パッケージ名がcom.google.android.apps.common.testing.ui.espressoからandroid.support.test.espressoになった
最初に書いたようにEspressoはGoogle製のフレームワークにも関わらず、今年に入って更新がほぼなくオワコン感があったのですが、今回の2.0はAndroid Support Repositoryの一つとなり、ドキュメントがAndroidDevelopersサイトへ移行予定とのことなのでAndoridとして推奨のUIテストフレームワークの一つに昇格したのではないかと思います。
1.Espresso1から2への移行をやってみる
Espresso1から2への移行を行ってみます。手順はこちらに記載があります。
EspressoSetupInstructions
最初から2を試したい人は以下に既にGoogleがサンプルプロジェクトを用意してるのでこちらを利用するのが手っ取り早いと思います。(ただし、AndoridSupportRepository最新版のダウンロードは必要)
Android-Testing Github Samples
最終的に変更したものはGithubに配置しています。(robolectric/deckard-gradleを利用して変更しました)
AndroidEspresso2Sample
なお、こちらにあるように実機かEmulatorで開発者メニューの一部は変更済みの想定です。
1–1.Espresso2.0を利用するように変更する
Espresssoに関連するjarファイルはAndroidSupportRepositoryから取得できるようになったので、lib配下のものは参照せず、パッケージ名を明記する方法にbuild.gradleを変更します。
- androidTestCompile files('lib/espresso-1.1.jar', 'lib/testrunner-1.1.jar', 'lib/testrunner-runtime-1.1.jar')
+ androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
+ androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
lib配下のjarファイルが不要になるので削除します。
$rm lib/espresso-1.1.jar
$rm lib/testrunner-1.1.jar
1–2.Espressoテストコードのパッケージ名を変更する
Espressoテストコードのパッケージ名をcom.google.android.apps.common.testing.ui.espressoからandroid.support.test.espressoに変更します。
-import static com.google.android.apps.common.testing.ui.espresso.Espresso.onView;
+import static android.support.test.espresso.Espresso.onView;
上記のように関連箇所を置換します。
1–3.Espresso2.0のダウンロード
AndroidSDKManagerを開いてExtra配下のAndroid Support Repositoryを最新版(rev11以上)をダウンロードします。
ダウンロードが成功すれば$ANDROID_HOME/extras/andorid/m2repository/com/andorid/support/test配下にespressoとtesting-support-libフォルダが存在が確認できます。testing-support-lib配下のpomを見るとjunit4.10に依存している記述があり、このファイルからもJUnit4対応が確認できます。
1–4.テストランナーの変更
テストランナーがGoogleInstrumentationTestRunneからAndroidJUnitRunnerになったのでbuild.graleを変更します。
- testInstrumentationRunner "com.google.android.apps.common.testing.testrunner.GoogleInstrumentationTestRunner"
+ testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
1–5.実行
エミュレーターや実機を繋いて以下を実行します。
$./gradlew clean connectedAndroidTest
成功していればBUILD SUCCESSFULと表示されると思います。
最終的なbuild.gradleは以下のようになりました。
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0-rc4'
}
}
allprojects {
repositories {
mavenCentral()
}
}
apply plugin: 'com.android.application'
android {
packagingOptions {
exclude 'LICENSE.txt'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE'
}
compileSdkVersion 19
buildToolsVersion "19.1.0"
defaultConfig {
minSdkVersion 18
targetSdkVersion 18
versionCode 2
versionName "1.0.0-SNAPSHOT"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
sourceSets {
androidTest {
setRoot('src/test')
}
}
}
dependencies {
repositories {
mavenCentral()
}
compile 'com.android.support:support-annotations:20.0.0'
// Espresso
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.0'
androidTestCompile 'com.android.support.test:testing-support-lib:0.1'
}
2.JUnit4のスタイルで書いてみる
せっかくなのでテストコードをJUnit4で書いてみることにしました。
ドキュメントは以下を参照。
User guide for AndroidJUnitRunner
なお、ドキュメントにも書いてあるようにJUnit3でも動くので特に昔のコードを変更する必要はなさそうです。
対応する場合には以下が必要です。
2–1.import文の追加
import org.junit.Before;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.InstrumentationRegistry;
2–2.RunWithアノテーションの追加
@RunWith(AndroidJUnit4.class)
@LargeTest
public class DeckardEspressoTest extends ActivityInstrumentationTestCase2<DeckardActivity> {
2–3.Before,Test,Afterのアノテーション追加
@Before
public void setUp() throws Exception {
・・・
}
@Test
public void testHoge() {
・・・
}
@After
public void tearDown() {
・・・
}
2–4.InstrumentationRegistryの実行
ActivityInstrumentationTestCase2を利用する場合、@Before内で手動で以下を実行する必要があるようです。
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
これを実行しないとgetActivityメソッドでnullが返却されてテスト結果がエラーとなってしまいました。
2–5.実行
エミュレーターや実機を繋いて以下を実行します。
$./gradlew clean connectedAndroidTest
今後の話
Espressoのリリースノートに
What about WebView support? While testing internally, we discovered some issues, which required major changes. We are putting the finishing touches on a new and improved API - it is coming shortly and it promises to be awesome.
とあるのでそのうちWebViewサポートがくるかもしれません。
また、Espressoではできないと思いますが、AndoridStudio1.1devでMockableJarタスクが追加されてているのでAndoridの単体テストは実機やエミュレーターががなくても実行できるようになりそうです。
android / platform/tools/base / e8f845b47459973838c99656ae98563b268f21ff^! / .
やってることとしてはASMを使ってandroid.jarのStubExceptionが発生させないように置き換えて各メソッドはデフォルト値を返すようにするようです。(挙動を変える場合にはmockitoを使うっぽい)