18日(米国時間)、JUnitの最新版となるJUnit 4.4が公開された。JUnitはJavaで開発されたユニットテストフレームワーク。Common Public License Version 1.0のもとに公開されているテストフレームワークで、ユニットテスト用のフレームワークとしては事実上の標準。後発のユニットテストフレームワークに比べて扱いが難しいと批判されることもあるが、4系からはアノテーションを導入するなどしてシンプル化が進められてきた。4.4ではいくつか新機能が導入されているのでここで紹介したい。

新しいアサーションメソッドの導入: assertThat

JUnitではテストを記述する方法としてアサーションメソッドを提供している。Assert.assertArrayEquals(...)などがそれにあたるもので、ほかにもassertEquals、assertFalse、assertNotNull、assertNotSame、assertNull、assertSame、assertTrueなどがある。アサーションメソッドを追加してサクサクッとチェック処理を挿入しようという発想だ。

JUnit 4.4では、新たに「Assert.assertThat(...)」というアサーションメソッドが導入されている。書式は次のとおりだが、ほかのアサーションメソッドと違ってassertThatでは比較処理を引数に指定できるようになっている。assertEqualsやassertTrueが特定の比較を実施するアサーションメソッドであるのに対して、assertThatは汎用的な比較を許可するアサーションメソッドである。従来のアサーションメソッドはすべてassertThatで置き換えることができるわけだ。

新しく導入されたAssert.assertThatメソッドの書式(JUnit 4.4リリースノートより抜粋)

assertThat([value], [matcher statement]);

JUnit 4.4に同梱されているリリースノートドキュメントには次の例が掲載されている。要するにこんな風に書けるということである。

Assert.assertThatメソッドの使用例(JUnit 4.4リリースノートより抜粋)

assertThat(x, is(3));
assertThat(x, is(not(4)));
assertThat(responseString, either(containsString("color")).or(containsString("colour")));
assertThat(myList, hasItem("3"));

assertThatにはいくつもの利点があるとされている。利便性の主張をまとめると次のようになる。

  • 従来のアサーションメソッドを使うよりもassertThatを使った記述の方が可読性が高く、何を比較するかがよくわかる
  • 従来のアサーションメソッドを使うよりもフェイラーメッセージの出力が理解しやすい
  • 比較処理の部分を他の比較処理と組み合わせ、否定、コレクションのマッピングなどとの組み合わせなど、さまざまな組み合わせを指定できる
  • 比較処理を自ら実装して使うことができる

assertTrueのフェイラーメッセージ

assertTrue(responseString.contains("color") || responseString.contains("colour"));
// ==> failure message: 
// java.lang.AssertionError:

assertThatのフェイラーメッセージ

assertThat(responseString, anyOf(containsString("color"), containsString("colour")));
// ==> failure message:
// java.lang.AssertionError: 
// Expected: (a string containing "color" or a string containing "colour")
//      got: "Please choose a font"

assertThatで従来のアサーションメソッドを置き換えることができるが、従来のアサーションメソッドがなくなることはないとされており引き続きサポートされるようだ。assertThatが導入されたからといってこれまでのアサーションメソッドが消えるわけではないので安心されたい。なお、この記法はもともと2005年5月13日(米国時間)に、Joe Walnes氏によって公開されたもの。この方法が優れていることから、今回4.4でそのまま取り込まれたようだ。

実装の話をしておくと、assertThatで2つめの引数に指定しているのはorg.hamcrest.Matcherを実装したクラスになっている。自分で比較処理を実装したければorg.hamcrest.Matcherを実装すればいい。あらかじめ実装された比較処理はorg.hamcrest.core.*にまとまっているので、こいつをimport staticしておけばいいというわけだ。

この比較処理を実装したクラスはThe Hamcrest Projectの成果物にまとまっているため、JUnitとしてははじめて、自分のプロジェクト以外の成果物としてHamcrestを同梱している。パッケージ名がorg.hamcrestになっているのは、これがJUnitの成果物ではなくThe Hamcrest Projectの成果物だからだ。

細かい改善や変更

JUnit 4.4では、ほかにも機能が追加されているが、それは改めて解説するとして、ここでは細かい改善や変更をまとめておこう。

まずassertEqualsや@Afterに関するバグが修正されている。そのほか、suite()メソッドを含んだテストクラスにおけるフィルタやソーターに関するバグも修正されている。バグ修正という意味でも4.4にアップグレードする価値はあるといえる。

機能面ではテストメソッドやテストクラスに記載されているディスクリプションにアノテーションを指定できるように機能が拡張されたほか、TestClassRunnerをリファクタリングしてJUnit4ClassRunnerとして変更、OldTestClassRunnerもJUnit3ClassRunnerへと変更されている。どのランナーが使われるかは、まず@RunWithアノテーションがあればアノテーションランナーが実行され、JUnit 3で実行できるようならJUnit38ClassRunnerが実行され、それ以外の場合にJUnit4ClassRunnerが実行される。この動作は@RunWith(JUnit4ClassRunner.class)や@RunWith(JUnit38ClassRunner.class)によって上書き可能とされている。

新機能を使うためにJUnit 4.4を導入するのもいいし、バグ修正という目的での導入もありだ。4.3以前の4系を使っている場合は4.4へのアップグレードを検討しよう。