JUnit Lambda Teamは先日JUnit 5のアルファリリースを発表した。人気の高いユニットテストフレームワークの新たなメジャーバージョンだ。プロジェクトに従事する開発者のフルタイム作業を実現するクラウドファンディングキャンペーンが成功した後,JUnit 5の変更作業の中心は,JUnit 4に存在した共通的な問題点の解決に加えて,将来の修正を容易にするためのフレームワーク変更にも向けることができるようになった。ビルドツールやIDEとの統合については,引き続き今後の課題となっている。
Release 5.0.0 Alphaを公開しました: https://t.co/Mb12F3WF4A
― JUnit Team (@junitteam) 2016年2月1日
開発者にとって嬉しいのは,彼らが日常的にユニットテストを書く方法にJUint 5が適応している点だ。例えばJUnitのFAQでは,慣習として単一のユニットテストに複数のアサーションを記述しないようにアドバイスしているが,事例証拠からは,そのような記述をする傾向にある開発者が多いことが分かっている。テストに複数のアサーションを含むリスクは,ひとつが失敗するとそのテストの実行がすぐに停止されるため,残ったアサーションが実行されないことだ。これに対してJUnit 5では,一部が失敗してもすべてのアサーションを実行する,グループアサーションの定義がサポートされるようになる。
@Test
void groupedAssertions() {
assertAll("address",
() -> assertEquals("John", address.getFirstName()),
() -> assertEquals("User", address.getLastName())
);
}
コードサンプルはJUnit 5 User Guideより引用。
もうひとつの共通的な不満は,例外テストのサポートに関するものだ。JUnit 4でサポートされている方法はどれも,開発者のニーズを完全には満足していない。方法のひとつとして,@Testアノテーションの“expected”オプションを使ってスローされるはずの例外の型を指定することが可能だが,スローされた例外のメッセージをチェックするといった,より複雑なアサーションの作成には柔軟性が十分だ。このような場合には,期待する例外とのマッチャ(matcher)の使用をサポートする@RuleとExpectedExceptionも利用できる。しかしながら,例外オブジェクト内のカスタムフィールドやメソッドなどをさらにテストしたり,例外をスローした以後のメソッド処理にアサーションを追加するような場合,ExpectedExceptionでは機能不足である。
これに対処するため,JUnit 5では,新たなアサーションとしてexpectThrowsが提供される。このアサーションでは,指定されたメソッドが期待される型の例外をスローすることをチェックするだけでなく,結果としてその例外オブジェクトを返すことにより,スロー以降のテストも実施が可能になる。
@Test
void exceptionTesting() {
Throwable exception = expectThrows(IllegalArgumentException.class,
() -> { throw new IllegalArgumentException("a message"); }
);
assertEquals("a message", exception.getMessage());
}
コードサンプルはJUnit 5 User Guideより引用。
拡張性も注目されている。JUnitを動作拡張する一般的な方法は,バージョン4では@RunWithを利用するものだった。しかしながら,@RunWithは各テストクラスに1度しか使用できないため,例えば,異なるデータを使って同じテストを実行するParameterizedや,モックを自動セットアップするMockitoJUnitRunnerとの併用はできない。JUnit 5では@RunWithに代えて,複数インスタンスの利用をサポートする新しい拡張機構である@ExtendWithが導入されている。
新バージョンへの段階的な移行を可能にするために,JUnit 5では,すべてのクラスが新しいパッケージに移動するとともに,大部分のアノテーションの名称が変更されている。JUnit Lambda Teamはさらに,JUnit 4を引き続きメインのテストフレームワークとして使用しながら,JUnit 5の全機能を使用可能にするという,JUnit Runner for JUnit4も開発している。これによって,JUnit 4とJUnit 5の同一プロジェクト内での共存が可能になると同時に,移行期間への対処も簡単になる。
最後に,セマンティックバージョニングとAPIのアノテーションを組み合わせることで,互換性のないものも含んだ将来的な機能変更にも注意が払われている。JUnit 5では,テストフレームワークのすべての公開クラスとインターフェースが,以下のいずれかの値でマークされる予定だ。
- Internal: フレームワーク外での使用を想定しないもので,常に事前の予告なく廃止される可能性がある。
- Deprecated: 使用を避けるべきで,次回のマイナリリースで削除される可能性がある。
- Experimental: 新たなコンセプトへのフィードバック収集を目的としたもので,次の段階に進むか,あるいは事前の予告なく廃止される。
- Maintained: 現在のバージョンから,少なくともマイナリリースでは後方互換性が維持される。廃止が予定された場合には,まずDeprecatedに変更される。
- Stable: 現在のメジャーリリースバージョンでは互換性が維持されている変更。
前回のメジャーリリースから10年が過ぎたが,JUnitは時代に追いついているようだ。ビルドツールやIDEとの統合に関する開発が依然として残る一方で,MavenやGradle用のプラグインは非常に高度であり,まだ暫くは中心的なJavaテストフレームワークの位置にあり続けると思われる。
この記事を評価
- 編集者評
- 編集長対応