EspressoでAndroidのUIテストコード

# Espressoとは
+ googleが開発を行っている。
+ AndroidのUIテストフレームワーク
+ 自動同期(Automatic Synchronization)
+ 基本的な操作が簡単にかける(テキスト入力、クリック、スクロール、スワイプ)
+ 自分が欲しいアクションが提供されていない場合は自分で作ることも可能
 
# 導入
gradleに以下のコードを追加
最新のバージョンは[公式サイト](http://developer.android.com/training/testing/ui-testing/espresso-testing.html)を参照してください。

```
dependencies {
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
}
```

# 新規登録画面のフローテスト
idとパスワードを入力し、ボタンを押すと次の画面へ遷移するアプリを考えます。
この時、登録に失敗した場合には上の方にエラーメッセージを表示します。
 
![image](https://qiita-image-store.s3.amazonaws.com/0/98416/d0aa854a-6b9c-a180-95a4-5d3d5d515635.png) ![image](https://qiita-image-store.s3.amazonaws.com/0/98416/258e788a-1e68-014a-8599-aafcdf07d875.png) ![image](https://qiita-image-store.s3.amazonaws.com/0/98416/a6eee3f2-577f-37ab-1ffb-53488c69f244.png)
 
### SignUp失敗時のテスト

```java
@Test
public void checkErrorMessage() {
	onView(withId(R.id.user_id)).perform(replaceText(""));
	onView(withId(R.id.password)).perform(replaceText(password), closeSoftKeyboard());
	onView(withId(R.id.signup_button)).perform(click());
	onView(withId(R.id.error_message)).check(matches(withText("ユーザーIDを入力してください。")));
}
```

### SignUp成功時のテスト

```java
@Test
public void checkSignUp() {
	onView(withId(R.id.user_id)).perform(replaceText(userId));
	onView(withId(R.id.password)).perform(replaceText(password), closeSoftKeyboard());
	onView(withId(R.id.signup_button)).perform(click());
	onView(withId(R.id.hello_world)).check(matches(withText("Hello World, " + userId + "!!")));
}
```

# CustomMatcher
先ほどの上の**withText**では画面上のテキストの値をチェックしていましたが、自分でカスタマイズしたMatcherも作ることができます。
例えばTextViewの色をチェックするCustomMatcherを実装するにはmatchesSafelyメソッドとdescribeToメソッドをオーバーライドします。
matchesSafelyで独自のMatcherを定義し、describeToでログの表示を定義します。

```java
private static Matcher<Object> withColor(final Matcher<Integer> integerMatcher) {
	return new BoundedMatcher<Object, TextView>(TextView.class) {
		@Override
		public boolean matchesSafely(TextView textView) {
			return integerMatcher.matches(textView.getCurrentTextColor());
		}

		@Override
		public void describeTo(Description description) {
			description.appendText("with resource color : ");
			integerMatcher.describeTo(description);
		}
	};
}
```

```java
onView(withId(R.id.error_message))
        .check(matches(withColor(is(ContextCompat.getColor(activity, android.R.color.holo_red_light)))));
```

# Idling Resource
ある条件を満たした後にアクションを行う。
アニメーションが終了した後にスクロールを開始する。5秒たった後にボタンを押下する。など。
これは、IdlingResourceをimplementsしたクラスで実装します。
以下はhoge秒後にアクションを行う処理を行う場合

```java
public class ElapsedTimeIdlingResource implements IdlingResource {
	private final long startTime;
	private final long waitingTime;
	private IdlingResource.ResourceCallback resourceCallback;

	public ElapsedTimeIdlingResource(long waitingTime) {
		this.startTime = System.currentTimeMillis();
		this.waitingTime = waitingTime;
	}

	@Override
	public String getName() {
		return ElapsedTimeIdlingResource.class.getName() + ":" + waitingTime;
	}

	@Override
	public boolean isIdleNow() {
		long elapsed = System.currentTimeMillis() - startTime;
		boolean idle = (elapsed >= waitingTime);
		if (idle) {
			resourceCallback.onTransitionToIdle();
		}
		return idle;
	}

	@Override
	public void registerIdleTransitionCallback(IdlingResource.ResourceCallback resourceCallback) {
		this.resourceCallback = resourceCallback;
	}
}

```

```java
@Test
public void checkErrorMessage() {
	// Now we wait 8 seconds for some reason
	IdlingResource idlingResource = new ElapsedTimeIdlingResource(DateUtils.SECOND_IN_MILLIS * 8);
	Espresso.registerIdlingResources(idlingResource);

	onView(withId(R.id.error_message)).check(matches(withColor(is(ContextCompat.getColor(activity, android.R.color.holo_red_light)))));

	// Clean up
	Espresso.unregisterIdlingResources(idlingResource);
}
```

# 考察
Espressoの文法は見た目がわかりやすく、コード量も少なくて済むのですごく良いです。
この記事のコードはGitHub上に[EspressoDemo](https://github.com/TakuSemba/EspressoDemo)という名前で公開しているので、ぜひ。

話は逸れますが、個人的にAndroidアプリ[MapMe](https://play.google.com/store/apps/details?id=com.takusemba.mapme&hl=jp)とNetflixの映画レビューサイト[WhatchaSee](https://whatcha-see.herokuapp.com/)を運営しています。
拝見していただけるとありがたいです。