最近知ったAssertJというテストライブラリを使ってみた
AssertJ / Fluent assertions for java
Fluent assertions
とあるように流れるようなassertionが出来ると聞いてちょっと気になった
AssertJの導入
gradleの設定
AssertJ / Fluent assertions for java
このページによるとAndroidだと1.x系がいいらしい
3.xまで出ているので何となく残念な気持ちになる
dependencies {
androidTestCompile 'org.assertj:assertj-core:1.+'
}
これで導入できる
いくつかのファイルをandroid.packagingOptions
でexlucde
指定する必要があるかも知れない
その場合は以下のようにすればまず問題ない
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
クラスを自分で実装したりする必要があった
例えばこんな感じ
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用にライブラリを提供している
dependencies {
androidTestCompile 'com.squareup.assertj:assertj-android:1.0.1'
}
これで`'org.assertj:assertj-core'も導入される
テストの書き方
普通のassertThat
と大体同じに書ける
AssertJ Android by Square, Inc.のページにあるようにisGone
やisVisible
が簡単に書けることが特長であるといえる
findViewById
などして取得したViewオブジェクトに対して例えばassertThat(<何かのView>).isVisible()
でassertThat(<何かのView>.getVisibility()).isEqualTo(View.VISIBLE)
と同じ事が出来る
Espressoとの比較
個人的にはViewのテストはAssertJよりEspressoの方が楽かなという印象
Viewのテストをそれぞれでやったテストファイル全体を載せるとこんな感じ
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\);
を入れればある程度置換出来た
すでに書かれたテストを置換するほどではないが、新しくテストを書き始めるならこれからはこちらを使えばいいと思う。