JUnit4の胎動

先日、Kent Beckのインタビュー記事 Developer Spotlight: Kent Beckを読んでいたら、以下のような記述に出会いました。

Erich Gamma and I are working on a new JUnit release that will mark its first significant architectural changes since JUnit was very young.

むむっ、significant architectural changesとはどのようなものなのでしょうか。


興味を持ってsfの中を探してみると...Version4というブランチがありました。もう開発が始まっているんですね。さっそくチェックアウトしてみました。

$ cvs -z3 -d:pserver:anonymous@cvs.sourceforge.net:/cvsroot/junit co -rVersion4 junit


少しいじってみたら色々分かってきましたので、現時点での所見をまとめてみたいと思います。ただし、JUnit4はまだ開発が始まったばかりのようなので、あくまで現時点でのレポートです。これからもいろいろ変更され、もっと便利になってゆくでしょう。期待しながらHEADを追いかけたいと思います。

またJUnit4の変更速度は比較的ゆっくりで、週末しかコミットされていないように見受けられます。Kent BeckもErich Gammaも忙しいのでしょう(当り前か)。
追記: どうやら二人でリモートペアプロしているみたいです。


と、ここまで書いていたら、かくたにさんの日記でErich Gammaも発言していることを知りました。Kent Beck,Erich Gamma二人とも発言を始めたんですね。



JUnit4の目指すもの

to-do.txtに以下の記述があります。

Theme: lower the barriers to entry and enable more sophisticated testing

「取っ付き易く、かつ洗練されたテストを可能にする」でしょうか。
ここにも「易しさと優しさ」ですね。


JUnit4の変更点

JUnit4の最大の変更点は「アノテーションの導入」です。significant architectural changesとは、多分アノテーションの導入のことでしょう。
ではアノテーションの導入によって何が得られるでしょうか。現時点で考えられる利点を挙げてみます。

  • クラスjunit.framework.TestCaseを継承する必要がなくなる
  • テストメソッド名を"test"で始めなくてよくなる
  • "setUp","tearDown"というメソッド名の縛りも不要になる
  • テストクラス単位の初期化が明確で簡単になる
  • 例外のテストが簡略化される
  • (おそらく)特定のテストを無視させることができるようになる
  • (おそらく)テストにカテゴリをつけることができるようになる


具体例はサンプルを見た方が早いと思いますので、サンプルを書いてみました。

  1  package com.example.junit4;
  2  
  3  import static org.junit.Assert.assertEquals;
  4  import static org.junit.Assert.assertTrue;
  5  
  6  import java.util.Arrays;
  7  import java.util.List;
  8  
  9  import junit.framework.JUnit4TestAdapter;
 10  
 11  import org.junit.After;
 12  import org.junit.AfterClass;
 13  import org.junit.Before;
 14  import org.junit.BeforeClass;
 15  import org.junit.Test;
 16  
 17  
 18  public class Junit4SampleTest {
 19  
 20    private String sampleStr;
 21    private static List<String> hugeData;
 22    
 23    public static junit.framework.Test suite() {
 24      return new JUnit4TestAdapter(Junit4SampleTest.class);
 25    }
 26    public static void main (String... args) {
 27      junit.textui.TestRunner.run (suite());
 28    }
 29  
 30    @Before
 31    public void インスタンス単位の前準備() {
 32      System.out.println("■インスタンス単位の前準備");
 33      this.sampleStr = "Hoge";
 34    }
 35    
 36    @BeforeClass
 37    public static void テストクラス単位の前準備() {
 38      System.out.println("▲テストクラス単位の前準備");
 39      hugeData = Arrays.asList("Per","Class","Setup");
 40    }
 41    
 42    @After
 43    public void インスタンス単位の後始末() {
 44      System.out.println("□インスタンス単位の後始末");
 45    }
 46    
 47    @AfterClass
 48    public static void テストクラス単位の後始末() {
 49      System.out.println("△テストクラス単位の後始末");
 50    }
 51    
 52    @Test
 53    public void 小文字に変換できる() {
 54      assertEquals("hoge", this.sampleStr.toLowerCase());
 55    }
 56    
 57    @Test
 58    public void 大きめのデータにアクセスする() {
 59      assertTrue(hugeData.contains("Per"));
 60    }
 61    
 62    @Test (expected=StringIndexOutOfBoundsException.class)
 63    public void 範囲外のインデックスにアクセスすると例外が発生すること() {
 64      this.sampleStr.charAt(30);
 65    }
 66  }

実行例

▲テストクラス単位の前準備
.■インスタンス単位の前準備
□インスタンス単位の後始末
.■インスタンス単位の前準備
□インスタンス単位の後始末
.■インスタンス単位の前準備
□インスタンス単位の後始末
△テストクラス単位の後始末

Time: 0.044

OK (3 tests)


JUnit4のアノテーションについて

30行目の@Beforeアノテーション、42行目の@AfterアノテーションはそれぞれsetUp,tearDownメソッドの仕事を果たします。


36行目の@BeforeClassアノテーション、47行目の@AfterClassアノテーションは、テストクラス単位での初期化処理と終了処理を司ります。これまでjunit.extensions.TestSetupを使って行っていた作業はここで書くようになるでしょう。個人的には現時点で最もJUnit3系との差が大きい部分だと思います。クラス単位の初期化が非常に書きやすくなりました。


@Testアノテーションはその名の通りテストメソッドを意味するアノテーションです。JUnit4は@Testの付いたメソッドをテスト対象と認識します。なお3,4行目でstatic importを行っているので、TestCaseを継承しなくてもテストメソッドの中で普通にassertEqualsやassertTrueを使用できます。


62行目では

@Test (expected=StringIndexOutOfBoundsException.class)

という書き方をしています。これは例外発生をテストする書き方で、従来では

public void test範囲外のインデックスにアクセスすると例外が発生すること() {
  try {
    this.sampleStr.charAt(30);
    fail();
  } catch (StringIndexOutOfBoundsException expected) {
  }
}

と書いていたようなテストの新しい書き方となります。



JUnit4のこれからを予想する

to-do.txtを見ていくと何点か面白そうな記述があります

@Ignore

@Ignoreアノテーションがついたメソッドはおそらく「無視されたことがレポートされる」ようになると思われます。NUnitの「黄色」のような状態でしょうか。この機能はNUnitの羨ましい機能のひとつでした。

test categorization & filtering (<- seems like a runner issue) @Category(short, integration) @Test(category=windowsOnly)

テストのカテゴライズが行われることになりそうです。ただ、書法はまだ悩んでいるみたいです。どういう判断がされるかを知ることが出来るのもHEAD追っかけの醍醐味と言えるのではないでしょうか。



追記: Erich Gammaはhttp://www.rojotek.com/blog/rob/archives/000076.htmlのコメント欄にて、

We are open for feedback and Kent and I intend to start blogging on our experiences soon.

と発言しています。楽しみになってきました。
個人的にはNUnitTestNGからのフィードバックを受けて、もっと使い易いものになればいいなと考えています。