AndroidでAssertJを使ってテストする


最近知ったAssertJというテストライブラリを使ってみた
[AssertJ / Fluent assertions for java](http://joel-costigliola.github.io/assertj/index.html)
>Fluent assertions

とあるように流れるようなassertionが出来ると聞いてちょっと気になった

# AssertJの導入

## gradleの設定

[AssertJ / Fluent assertions for java](http://joel-costigliola.github.io/assertj/assertj-core.html)
このページによるとAndroidだと1.x系がいいらしい
3.xまで出ているので何となく残念な気持ちになる

```groovy:build.gradle
dependencies {
    androidTestCompile 'org.assertj:assertj-core:1.+'
}
```

これで導入できる
いくつかのファイルを`android.packagingOptions`で`exlucde`指定する必要があるかも知れない
その場合は以下のようにすればまず問題ない

```groovy:build.gradle
android {
    packagingOptions {
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'NOTICE.txt'
        exclude 'LICENSE.txt'
        exclude 'DEPENDENCIES'
        exclude 'NOTICE'
        exclude 'LICENSE'
        exclude 'asm-license.txt'
    }
}    
```

## テストの書き方

テストファイルで`assertThat`をimportする

```java
import static org.assertj.core.api.Assertions.assertThat;
```

これで例えばあるオブジェクトが`null`かどうかをチェックするなら以下のように書ける

```java
assertThat(hogeObject).isNotNull();
```

このように`assertThat(<テスト対象>).isXXX(<期待値>)`のように流れるように書けるため、書きやすく読みやすいと感じる

また、正規表現で文字列を`assertThat`したいとき、junitだと`Matcher`クラスを自分で実装したりする必要があった
例えばこんな感じ

```java:RegexStringMatcher.java
class RegexStringMatcher extends BaseMatcher {
    private final Pattern mExpectedPattern;

    public RegexStringMatcher(String expected) {
        mExpectedPattern = Pattern.compile(expected);
    }

    public static RegexStringMatcher isMatch(String expected) {
        return new RegexStringMatcher(expected);
    }

    @Override
    public boolean matches(Object actual) {
        String actualStr = (String) actual;
        Matcher matcher = mExpectedPattern.matcher(actualStr);
        return matcher.find();
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("pattern: ").appendText(mExpectedPattern.pattern());
    }
}
```

この`RegexMatcher`をimportして`assertThat(hogeString, RegexStringMatcher.isMatch(pattern));`のようにする必要があった
これがAssertJだと`        assertThat(hogeString).matches(pattern);`のようにさくっと書けて最高

よく使うのは`isEqualTo`,`isNotNull`,`isNull`,`isInstanceOf`,`hasSize`,`matches`といったところ。
いろいろあるので[AssertJの公式](http://joel-costigliola.github.io/assertj/)を参照

# Viewのテスト

## 導入

いつものごとく、Square様がandroid用にライブラリを提供している

```groovy:build.gradle
dependencies {
	androidTestCompile 'com.squareup.assertj:assertj-android:1.0.1'
}
```

これで`'org.assertj:assertj-core'も導入される

## テストの書き方

普通の`assertThat`と大体同じに書ける
[AssertJ Android by Square, Inc.](http://square.github.io/assertj-android/)のページにあるように`isGone`や`isVisible`が簡単に書けることが特長であるといえる

`findViewById`などして取得したViewオブジェクトに対して例えば`assertThat(<何かのView>).isVisible()`で`assertThat(<何かのView>.getVisibility()).isEqualTo(View.VISIBLE)`と同じ事が出来る

### Espressoとの比較

個人的にはViewのテストはAssertJよりEspressoの方が楽かなという印象
Viewのテストをそれぞれでやったテストファイル全体を載せるとこんな感じ

```java:ExampleActivityTest.java

import android.app.Activity;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.MediumTest;
import android.widget.Button;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static org.assertj.android.api.Assertions.assertThat;

@RunWith(AndroidJUnit4.class)
@MediumTest
public class ExampleActivityTest {
    Activity mActivity;
    @Rule
    public ActivityTestRule<StartActivity> activityRule = new ActivityTestRule<>(ExampleActivity.class);

    @Before
    public void setUp() throws Exception {
        mActivity = activityRule.getActivity();
        assertThat(mActivity).isNotNull();
    }

    @Test
    public void 画面が表示されているかどうか() {
        onView(isDisplayed());
    }

    @Test
    public void ボタンのテストwithEspresso() {
        onView(withId(R.id.awesome_button)).check(matches(isDisplayed()));
        onView(withId(R.id.awesome_button)).perform(click());
    }

    @Test
    public void ボタンのテストwithAssertJ() {
        final Button button = (Button) mActivity.findViewById(R.id.awesome_button);
        assertThat(button).isNotNull().isVisible();
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                button.performClick();
            }
        });
    }
}
```

AssertJを使うと一旦`findViewById`をしてインスタンスを取得して、それに対してassertionを行うことになる
また、上に示したように例えば`perfomeClick`するためには`Activity#runOnUiThread`を介する必要が生じてしまう

それに対してEspressoであれば`onView(withId(<id>)).perform(click())`だけで書けるため、コード量も減ることとなる

本当に簡単なnullチェックやvisiblityチェックだけのテストであればAssertJでいいと思うが、ちょっと細かいことをするならあまりおすすめ出来ない感じではある

# 所感

先日のAndroidオールスターズでの発表をきいてAssertJの存在を知った
[RECRUIT TECHNOLOGIES Member's blog Androidオールスターズでテストの話をしました](http://blog.recruit-tech.co.jp/2015/08/10/android-allstars-201508/)

JUnitよりもAssertJの方が個人的には流れるように書けるため、書きやすく読みやすいように感じる

[JavaのテストにはAssertJがオススメ - Qiita](http://qiita.com/ikemo/items/165f01740995245f9009)
こちらの記事で紹介されているようにカスタムAssertionの実装も簡単に出来て、個人差はあると思うが全体的にJUnitよりちょっと良い、という感覚

また、公式でもJUnitからのマイグレーションについて記述があり、比較的移行も簡単だと思う
[convert your JUnit assertions to AssertJ](http://joel-costigliola.github.io/assertj/assertj-core-converting-junit-assertions-to-assertj.html#automatic-conversion)
とりあえずAndroid Studioの置換窓に

- before
	- `assertThat\((.+), is\((.+)\)\);`
- after
	- `assertThat\($1\).isEqualTo\($2\);`

を入れればある程度置換出来た
すでに書かれたテストを置換するほどではないが、新しくテストを書き始めるならこれからはこちらを使えばいいと思う。