読者です 読者をやめる 読者になる 読者になる

日々常々

ふつうのプログラマがあたりまえにしたいこと。

assertThat で Collection.isEmpty() を判定させたい

昔は assertTrue や assertEquals を使っていたのですが、時代は変わって assertThat が出来ています。使うことでのメリットは"テストコードの可読性向上"です。散らかりがちになるテストコードの可読性に関わるならば、使わない手はありません。
初めて見たときは正直「コレのナニが嬉しいんだ?」と疑問でしたけど、最近は基本的に assertThat しか使っていません。テストコードの読みやすさが全然違いますもん。

assertThat は単独では微妙です。例えば null の判定の場合、下記の様に書けますが assertNull の方が直感的でいい気もします。なお is は付けても付けなくても結果は変わりません。使い始めのころは一体何の為にあるのか判らなくて省略していました。今はつけるようにしています。

assertNull(obj);
assertThat(obj, is(nullValue()));

assertThat(と2番目のパラメータに入るMatcher)が効果を発揮するのは、複数の assert が存在する場合です。assertNull や assertEquals で判定する為には、値を取得して判定できる形に編集する必要があります。編集することでテストコードに余計なロジックが入ります。また、assertNull, assertEquals, assertFalse, assertTrue, assertSame... などなど assert メソッドを見て判断する必要が出てきます。これらのメソッド、ぱっと見た感じだと同じように見えることもあるんですよね。ぱっと見て判断できないテストコードは少々問題があります。

これに対し、一律 assertThat を使っていると、メソッド名と1番目のパラメータを見る必要がなくなります。2番目の Matcher にだけ注目すればいいので、見間違いも減りますし、何を判定したいかが判りやすい、はずです。日本人には微妙かもしれませんけど。


で、前述のメリットを叩き潰しやがることがありまして。Collection の空判定です。null は良いんですけれど、空を判定しようとしるとちょっと困ったことに。

assertThat(actual, is(not(nullValue())));
assertThat(actual.isEmpty(), is(true);

……こんなのしちゃうなら assertTrue(actual.isEmpty()) の方がマシに思います。思っちゃうと assertThat の布教が出来ませんのでダメです。ちょっと検索すると Collection.isEmpty() の Matcher が欲しい的なのは見るんですけど、今の JUnit(4.8) には無い……と思います。ですんで作ります。えいやーと。

public class CollectionEmpty extends TypeSafeMatcher<Collection<?>> {

	@Override
	public boolean matchesSafely(Collection<?> item) {
		return item.isEmpty();
	}

	public void describeTo(Description description) {
		description.appendText("empty");
	}

	public static Matcher<Collection<?>> empty() {
		return new CollectionEmpty();
	}
}

これですんなり書けるハズです。

assertThat(actual, is(empty()));

でも空判断したいのは Collection に限った話じゃないよねーと。例えば String です。 String.isEmpty() とか Java1.6 から出来たくらいですから、需要はあるでしょう。他には配列……配列は無い気がしてきたけど、一応配列も。後は isEmpty メソッドもってる何かーとか。その辺を盛り込むと こんな感じ(GitHub) になりました。

この程度だったら Gist の方がいいよなーとか思いつつも GitHub に入れちまったので、気が向いたら他のも突っ込んでいこうと思うのでした。