What is it, naokirin?

EspressoでAndroidのUIテストを始めよう(with Android Studio)

と言いつつEspressoによるUIのテストは初心者です。

今回はAndroid StudioでEspressoによるUIテストをやってみたので、その導入と初歩的なコードを書きのこしておくことにします。

Android Studioでプロジェクトを作成するのは特に特別なことはしないため、割愛します。なお、コードはKotlinで書いています。

Espressoなテストを書く準備をしよう

Espressoでテストコードを書いていく際に、Android Studioで作成したプロジェクトでは espresso-core は最初から使用できるようになっていますが、その他の必要なパッケージが不足しているため、それらを build.gradle に追加しましょう。普通に作成したプロジェクトであれば、プロジェクトルートと app 以下の2つに build.gradle があるかと思いますが、追加するのは app 以下の build.gradle です。

dependencies {
    /* 〜省略〜 */
    androidTestImplementation 'com.android.support.test.espresso:espresso-intents:3.0.2'
    androidTestImplementation 'com.android.support.test:rules:1.0.2'
}

上記を追加すると、エディタ上部に以下のような表示が出るので、その右の「Sync Now」をクリックして依存パッケージのインストールをしましょう。

f:id:naokirin:20190103152626p:plain

これで準備は完了です。

Espressoを使ってUIのテストを書いてみる

一旦サンプルのアプリを作成した上で、簡単なテストコードを書いてみます。

まずは最初に作成されるActivityにTextViewとButtonを配置してみましょう。IDはデフォルトのまま(textView, button)で、位置などは特に気にせず配置して大丈夫です。

f:id:naokirin:20190103154458p:plain

対応するコードとして、ボタンを押すとTextViewの文字列が変更されるようにしてみます。

package com.example.espressosample

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.button)
        button.setOnClickListener {
            val textView = findViewById<TextView>(R.id.textView)
            textView.text = "changed"
        }
    }
}

それでは、このアプリでボタンを押したら文字列が変更されることをテストしてみましょう。

Android Studioでプロジェクトを作成すると、 ExampleInstrumentedTest が追加されています。 src/app/androidTest 以下にあります。同じ場所に ChangedTextInstrumentedTest というクラスを追加しましょう。

そして以下のように実装をします。

package com.example.espressosample

import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.click
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.withId
import android.support.test.espresso.matcher.ViewMatchers.withText
import android.support.test.filters.LargeTest
import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@LargeTest
@RunWith(AndroidJUnit4::class)
class ChangedTextTest {

    @Rule
    @JvmField
    var mActivityTestRule = ActivityTestRule(MainActivity::class.java)

    @Test
    fun changedTextViewMainActivityTest() {
        val textView = onView(withId(R.id.textView))
        textView.check(matches(withText("sample text")))

        val button = onView(withId(R.id.button))
        button.perform(click())

        textView.check(matches(withText("changed")))
    }
}

それではまず実行してみましょう。Android StudioのProjectビューから、作成したテストを右クリックして、「Run ...」をクリックします。

f:id:naokirin:20190103162854p:plain

このあとデバイスの選択が出るので、デバイス選択をするとテストが実行されます。

上記のコードでいくつかのポイントを記します。これらは基本的にテストクラスで共通することになるかと思います。

  • LargeTest/MediumTest/SmallTest アノテーションを用いることで、特定の大きさのテストだけを実行させることができます
  • ActivityTestRule はUIスレッドでのテストを実行でき、また指定したActivityによるテストを実行することができます

それでは、実際のテストメソッド内を見ていくことにしましょう。

val textView = onView(withId(R.id.textView))
textView.check(matches(withText("sample text")))

val button = onView(withId(R.id.button))
button.perform(click())

textView.check(matches(withText("changed")))

onView() は引数のMatcherによりマッチしたViewを取得します。そしてそれらのViewの状態をチェックしたり操作したりできます。

onView() で利用できる主なMatcherを列挙します。が、これ以外にも多数存在するので、実際に使いたいものを探すには以下のリンクを参照してください。

android.support.test.espresso.matcher  |  Android Developers

名前 内容
withId IDが一致するか
allOf 複数のMatcher全てにマッチするか
anyOf 複数のMatcherのいずれかにマッチするか
isDisplayed Viewが表示されているか
isEnabled isEnabled() がtrueか
isClickable クリック可能か
withClassName クラス名にマッチするか

さて、 onView() で取得したViewの情報に対し、 check() でそのViewの状態をテストすることができます。こちらも、 onView で用いるMatcherを用いることができます。

残った perform() ですが、UI操作をすることができます。引数に複数のアクションを指定することができます。

android.support.test.espresso.action  |  Android Developers

こちらも主なものだけを列挙します。

名前 内容
click 対象のViewをクリックする
doubleClick 対象のViewをダブルクリックする
longClick 対象のViewをロングクリックする
pressBack バックボタンを押す
scrollTo 指定したViewまでスクロールする
typeText EditTextに指定した文字列を入力する

その他のアサーション

これまでに書いたもの以外にも、Intentに対するテストや AdapterView (List/GridView)へのテストに利用する onData() などもあります。

このあたりはまだ勉強中なのですが、この記事の最初にインストールしたパッケージ指定があれば使用可能になっているはずです。

まとめ

Espressoを利用しない場合でもUIのテストは可能なようですが、Espressoを使うことで読みやすい形で表現することができるようになります。ただ、便利ですが、ユニットテストよりもテストにかかる時間が長いので、あまり頼りすぎずにユニットテストと使い分けながら効果的に利用していきたいですね。