ExpectedExceptionがなかった時代は、try-catchで例外補足してアサートしていたのでかなりの便利機能だと思う。
※@Testアノテーションのexpected属性だと、発生する例外のクラスしかアサートできなかったので、これは使い物にならなかった。
使い方
テストクラスのインスタンス変数で、ExpectedExceptionを宣言する。
ルールであることを示す、@Ruleアノテーションを設定する。
宣言時には、ExpectedException.noneを代入することで、例外が発生しないことを期待するようにしておく。
@Rule public ExpectedException expectedException = ExpectedException.none();
例外をアサートする場合には、例外が発生することを期待するテストケースのメソッドで、アサートする内容をExpectedExceptionに設定する。
このケースだと、NullPointerExceptionが発生してそのメッセージには「error」が保持されていることを期待している。
@Test public void nullPointerException() throws Exception { expectedException.expect(NullPointerException.class); expectedException.expectMessage("error"); throw new NullPointerException("error"); }
元例外(cause)をアサーとしたい場合は、expectCauseにMatcherを登録する。
この例では、causeの例外クラスがNullPointerExceptionであることをアサーとしている。
expectedException.expect(CustomException.class); expectedException.expectCause(instanceOf(NullPointerException.class)); throw new CustomException(new NullPointerException());
メッセージやcause以外の属性をアサートする場合には、カスタムのMatcherを作ると良い。
例えば、SQLExceptionのベンダーコード(getErrorCode)をアサートする場合には以下のようなMatcherを作る。
public static class IsSqlErrorCode extends TypeSafeMatcher{ private final int expectedSqlErrorCode; public IsSqlErrorCode(int expectedSqlErrorCode) { this.expectedSqlErrorCode = expectedSqlErrorCode; } public static IsSqlErrorCode isSqlErrorCode(int expectedSqlErrorCode) { return new IsSqlErrorCode(expectedSqlErrorCode); } @Override protected boolean matchesSafely(SQLException e) { return e.getErrorCode() == expectedSqlErrorCode; } @Override public void describeTo(Description description) { description.appendText("exception with the error code ") .appendValue(expectedSqlErrorCode); } @Override protected void describeMismatchSafely(SQLException item, Description mismatchDescription) { mismatchDescription.appendText("error code was ") .appendValue(item.getErrorCode()); } }
Matcherの使い方は・・・
expectedException.expect(SQLException.class); expectedException.expect(IsSqlErrorCode.isSqlErrorCode(1)); throw new SQLException("sql error", null, 1);