AndroidTestでNavigationView操作したいよね?
ちょっと前に静かにReleaseされていたEspresso 2.2.2にNavigationViewを操作するNavigationViewActionsというのが追加されていたのでそのお話。
NavigationViewの基本的な使い方は以下のQiitaにお任せするぜー。
"NavigationViewを使ってGoogle Play風のメニューを作る【Android Design Support Library】"
http://qiita.com/chuross/items/60af0aca3e1c3f946f09
DrawerLayoutとNavigationViewは仲良しこよし
まず、NavigationViewの各メニューの特徴として、それぞれのメニューが個別のidを持っているってこと。
「あーならそのid指定してどれ選択するか書いてあげればいいのねー」ってことになる。
ただNavigationViewは基本的にDrawerLayoutの子Viewとして追加して使うことが多いと思ってる。
DroidKaigiアプリのTop画面のレイアウトとか見るとまあわかると思う。以下のようにDrawerLayoutの子ViewとしてNavigationViewを使ってる。
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="io.github.droidkaigi.confsched.activity.MainActivity">
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
....
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header"
app:itemTextColor="@color/nav_view_colors"
app:menu="@menu/drawer_menu"
app:insetForeground="#4000"/>
</android.support.v4.widget.DrawerLayout>
</layout>
何が言いたいのかというと、NavigationViewをNavigationViewActionsで操作するには、まずはDrawerLayoutをOpenしないとNavigationViewの各メニューがUI上表示されなくて操作できないってこと。
DrawerLayoutをOpenしないまま後ほど紹介するNavigationViewActionsを使うと以下のように
「Clickできないー(´・ω・`)」ってエラーが出ます。
android.support.test.espresso.PerformException:
Error performing 'click on menu item with id' on view 'with id:
io.github.droidkaigi.confsched.develop.debug:id/nav_view'.
NavigationViewActionsの使い方
ではでは、以上のことをふまえてDroidKaigiアプリのNavigationViewの各メニューを操作してAndroidTestでそれぞれの画面を表示してみた。
まずは、build.gradleのdependenciesにEspresso2.2.2とかもろもそ追加します。
雑にdependencies部分だけ抜き出し。ちなみに、使ってるsupport libによってバージョンが違うぞ!とか怒られるので、Espressoに含まれてるものはexcludeで抜いておくのがいいよ。
dependencies {
compile "com.android.support:appcompat-v7:23.2.0"
compile "com.android.support:design:23.2.0"
androidTestCompile('com.android.support.test:runner:0.5') {
exclude group: 'com.android.support', module: 'support-annotations'
}
androidTestCompile('com.android.support.test:rules:0.5') {
exclude group: 'com.android.support', module: 'support-annotations'
}
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2') {
exclude group: 'com.android.support', module: 'support-annotations'
}
androidTestCompile('com.android.support.test.espresso:espresso-intents:2.2.2') {
exclude group: 'com.android.support', module: 'support-annotations'
}
androidTestCompile ('com.android.support.test.espresso:espresso-contrib:2.2.2') {
exclude group: 'com.android.support', module: 'support-annotations'
exclude group: 'com.android.support', module: 'support-v4'
exclude group: 'com.android.support', module: 'recyclerview-v7'
exclude group: 'com.android.support', module: 'appcompat-v7'
exclude group: 'com.android.support', module: 'design'
}
}
テストコード側は以下のようにDrawerLayout Open -> NavigationViewActions.navigateTo(id)を繰り返して各メニューを開いていく。
Thread.sleepは開いたのをちゃんと目視するためにメニューが切り替わったらちょっと止めてるだけ。
@RunWith(AndroidJUnit4.class)
public class MainActivityTest {
@Rule
public IntentsTestRule<MainActivity> activityRule = new IntentsTestRule<>(MainActivity.class);
@Test
public void test_navigation_view() throws InterruptedException {
onView(withId(R.id.drawer)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_my_schedule));
Thread.sleep(1500);
onView(withId(R.id.drawer)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_map));
Thread.sleep(1500);
onView(withId(R.id.drawer)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_settings));
Thread.sleep(1500);
onView(withId(R.id.drawer)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_sponsors));
Thread.sleep(1500);
onView(withId(R.id.drawer)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_about));
Thread.sleep(1500);
onView(withId(R.id.drawer)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_all_sessions));
Thread.sleep(1500);
}
}
基本は以下の二行です。
DrawerActions.open
でDrawerLayoutを開くとUI上にNavigationViewの各メニューが表示されるので、NavigationViewActions.navigateTo(id)
で選択したいメニューのidを引数に渡します。
onView(withId(R.id.drawer)).perform(DrawerActions.open());
onView(withId(R.id.nav_view)).perform(NavigationViewActions.navigateTo(R.id.nav_all_sessions));
ちょっと注意して欲しいのはDrawerLayoutをOpenする方法はDrawerActions.openを使いのがよいです。
昔はDrawerActions.openDrawerってものがあったんだけど、これはDeprecatedになってます。
// Good!!
onView(withId(R.id.drawer)).perform(DrawerActions.open());
// Deprecated!! NO!!
DrawerActions.openDrawer(R.id.drawer);
端末上で動かすと以下のような感じでちゃんとDrawerLayoutをOpenしてNavigationViewの各メニューを選択して画面が切り替わってます。
NavigationViewActionsの情報
以上のような感じでNavigationViewをNavigationViewActionsで操作できたわけですが、そもそもこれいつ追加されたんやー!!って話なんですよ。
んで、これを見つけたきっかけはちらっと以下のAndroid Testing Support LibraryのRelease Notesを見たのがきっかけ。
Espresso 2.2.2, Runner/Rules 0.5 (2016-02-22, silent release)
New Features
- espresso
- Issue 194253: Add support for NavigationView in android support design library
ほむほむ。Espresso 2.2.2でNavigationViewの操作をSupportしたよ!!って感じ。
んじゃ、NavigationViewを操作するクラスなによ??って話で、EspressoのJavadoc見てみた。
「Classes見れば追加されてるはずだよねー♪」
...(´・ω・`)
お分かりいただけるだろうか
なんとJavadocにNavigationViewActionsが追加されていない。
どうやらEspresso 2.2.2, Runner/Rules 0.5 のRelease内容がJavadocに反映されていない。
Silent Releaseだから??それとも別に最新のJavadocあるの??知っている人いたら教えてほしい...。
ローカルのjarとか見ればNavigationViewActionsの実装見れるけど面倒は人はNavigationViewActionsの中身をGistに移したので参考までに。
ちなみに、NavigationViewActionsの実装は元々android-testingのcustom actionとして実装されていたものをほぼほぼそのまま採用したっぽい実装になっている。
NavigationViewActions Sample
NavigationViewActionsを使った雑なSampleを作ったみたので手元で動かしたい人はこれで試してみてください。
まとめ
NavigationViewが簡単に操作できるようになってめでたしめでたしでした。