2018/6/13追記
jUtaime は JUnit5 の登場によりその使命を終えました。
長らくご愛顧ありがとうございました m(_ _)m
みなさま JUnit5 を使いましょう。
What's an issue ?
JUnitでの例外検証コードをもっとスッキリ書きたいっ!
そう思っているのはきっと私だけではないはず・・・
before
例えば Person#setAge(int)
なんていうよくあるメソッドを作ったとして、次の4点を検証したい。
-
setAge(-1)
は NG →IllegalArgumentException
をスロー -
setAge(0)
は OK -
setAge(200)
は OK : 超長寿社会の到来に備えて。 -
setAge(201)
は NG →IllegalArgumentException
をスロー、例外メッセージあり
通常のJUnit4ではこんな感じになると思います。
public class PersonTest {
private Person person = new Person("John");
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test(expected = IllegalArgumentException.class)
public void testSetAge1() {
person.setAge(-1);
}
@Test
public void testSetAge2() {
try {
person.setAge(0);
person.setAge(200); // 200歳まではOKとする。
} catch(RuntimeException e) {
fail();
}
}
@Test
public void testSetAge3() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Is he a zombie!?");
person.setAge(201);
}
}
なーんでたったこれっぽっちの検証で、こんなにもっさりしたコードを書かなきゃいけないんですかね! ぷんぷん
after
これで良いじゃん...
public class PersonTest {
@Test
public void testSetAge() {
Person p = new Person("John");
assertThat(of(() -> p.setAge(-1)), raise(IllegalArgumentException.class));
assertThat(of(() -> p.setAge(0)), raiseNothing());
assertThat(of(() -> p.setAge(200)), raiseNothing());
assertThat(of(() -> p.setAge(201)), raise(IllegalArgumentException.class, "Is he a zombie!?"));
}
}
so that
というわけで、afterを実現するライブラリを作りました。
nmby/jetaime · GitHub
nmby/jUtaime · GitHub (2015/7/26 移動しました。)
usage
- 例外をスローしうる検証対象の処理を、
Testee.of()
の中に記述します。 - 期待する例外の型やメッセージ、原因(cause)の型などを、
RaiseMatchers.raise()
などで指定します。
assertThat(Testee.of(SomeClass::someMethodShouldFail),
RaiseMatchers.raise(SomeException.class, "expected message"));
Testee
と RaiseMatchers
は static インポートしておくとよいでしょう。
次のような色々な書き方が可能です。
assertThat(of(() -> Integer.valueOf("abc")), raiseExact(NumberFormatException.class));
assertThat(of(() -> Integer.valueOf("123")), raiseNothing());
assertThat(of(() -> { Object o = null; o.toString(); }), raise(RuntimeException.class));
assertThat(of(obj::dbOperation), rootCause(IOException.class));
また、他の Matcher と組み合わせて使用することもできます。
次の例では、hamcrest.org が提供する anyOf
、allOf
、not
と組み合わせて使用しています。
// NullPointerException または IllegalArgumentException がスローされることを検証
assertThat(of(() -> obj.someOperation(null)),
anyOf(raise(NullPointerException.class), raise(IllegalArgumentException.class)));
// NullPointerException 以外の何らかの実行時例外を原因として上位例外がスローされることを検証
assertThat(of(() -> obj.someOperation(param)),
allOf(raise(WrappingException.class, "expected message"),
rootCause(RuntimeException.class),
not(rootCause(NullPointerException.class))));
allOf()
の代わりに、次の連結スタイルで記述することも可能です。
// NullPointerException 以外の何らかの実行時例外を原因として上位例外がスローされることを検証
assertThat(of(() -> obj.someOperation(param)),
raise(WrappingException.class, "expected message")
.rootCause(RuntimeException.class)
.not(rootCause(NullPointerException.class)));
詳しくは javadoc を見てね♪
なお、eclipseで使えばちゃんとレポートも表示されます。
dependencies
- java 8 以上が必要です。
- hamcrest-core も必要ですが、JUnit4を使ってるならすでに入ってるはずです。