JUnit4の落とし穴(アノテーションは継承されない)

うーん,落とし穴っていうほど大げさなモノじゃないんだけど,JUnit3当たり前にできてたことがJUnit4でできないものもあるよって話。その代表例が,アノテーションの継承ができない事。


事の善し悪しは置いておくが,よくテストケースのバリエーション作りに,親(抽象)クラスに基本となるテストメソッドを定義しておき,それをテンプレとして子(具象)クラスでパラメタ変えたりしてたわけだ。簡単にコードで示すとこんな事。

public class JUnit3Super extends TestCase {
    public void testテストケース1() { ... }
    public void testテストケース2() { ... }
}

public class JUnit3SampleTest extends JUnit3Super {
}

当たり前だが,JUnit3SampleTestにはJUnit3Superのテストケースが継承されるので,問題なくテストを実行できる。だけど,これがJUnit4になるとそうはいかない。JUni4流に書き直すと,

public class JUnit4Super {
    @Test public void テストケース1() { ... }
    @Test public void テストケース2() { ... }
}

public class JUnit4SampleTest extends JUnit4Super {
}

って感じなるんだが,残念なことにアノテーションは継承されないので,JUnit4SampleTestはテストハーネスとして認識されんのだ。こんな事はJDK5の言語仕様を知ってりゃ,至極当然のことなので,なにも騒ぎ立てる話じゃないんだけど,まあちょっと残念ではある。


ここでちょっと視点を変えるが,JUnit3/JUnit4と区別して話をしているが,JUnit4のJarファイル(junit-4.4.jarとかjunit-4.3.jar)にはJUnit3も含まれているのだ(JUnit4のorg.junitパッケージだけじゃなく,JUnit3のjunit.frameworkパッケージも含まれている)。
だから,テストケースはJUnit3流でアサーションはJUnit4流,なんてハイブリッドだってOKなのだ。

import junit.framework.TestCase;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;

public class JUnit34Test extends TestCase {
    public void testテスト() {
        assertThat(true, is(true));
    }
}

スクリーンショットを貼れないのが残念だが,IDEAで試してみたらJUnit3流/JUnit4流/そのハイブリッドが同じテストディレクトリに混在していても,すべてテストケースと認識したしテストの実行もできた。だから,JUnit4を使ったからと言ってムリに@Testアノテーションを使う必要はないのかも知れない。
#他のIDE?そんなの知らんよ。:-P


なんにせよ,JUnit4に慣れるまで,もちょっと試行錯誤が必要だ。


(追記)コメントより,JUnitのテストランナーはクラス階層をさかのぼってアノテーションを判別してくれる。なんで,イケてないのは,@Testアノテーションがないとテストハーネスだと認識できないIDE側だったという話。
テストランナーに載せてしまえばこっちのものなので,IDEをだまくらかすために,こんなふうにダミーを置いておく手もあるが,それってどうなんだろ?

public class JUnit4Super {
    @Test public void テストケース1() { ... }
    @Test public void テストケース2() { ... }
}

public class JUnit4SampleTest extends JUnit4Super {
    @Test public void ダミー() {}
}