17
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

最近知ったAssertJというテストライブラリを使ってみた
AssertJ / Fluent assertions for java

Fluent assertions

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

AssertJの導入

gradleの設定

AssertJ / Fluent assertions for java
このページによるとAndroidだと1.x系がいいらしい
3.xまで出ているので何となく残念な気持ちになる

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

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

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する

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

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

assertThat(hogeObject).isNotNull();

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

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

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の公式を参照

Viewのテスト

導入

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

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

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

テストの書き方

普通のassertThatと大体同じに書ける
AssertJ Android by Square, Inc.のページにあるようにisGoneisVisibleが簡単に書けることが特長であるといえる

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

Espressoとの比較

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

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オールスターズでテストの話をしました

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

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

また、公式でもJUnitからのマイグレーションについて記述があり、比較的移行も簡単だと思う
convert your JUnit assertions to AssertJ
とりあえずAndroid Studioの置換窓に

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

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

17
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?