torutkのブログ

ソフトウェア・エンジニアのブログ

JUnit4の更新

今月のJava読書会では時間があまりそうなので、ネタを検討中です。ネタ候補の一つにアノテーション・プログラミングの事例を考えています。そこで、JUnit 4を先取りしてその実装の一部を調べています。

JUnit 4は開発途上のため、CVSからソースを入手してビルドします。9月に一度ビルドしていたのですが、今日更新(cvs update)をかけてビルドしたらエラーの山。cvsはupdateする際に-dオプションを付けないと新しくリポジトリに追加されたディレクトリは作業ディレクトリに持ってきてくれません。そこで、-dオプションを付けて再度cvs updateを実行し、それからantを実行してビルドしました。

JUnitソースコードの入手

http://sourceforge.net/cvs/?group_id=15278cvsによる入手方法が記載されているので、それに従ってソースを入手します。ただし、JUnit 4は、既存のJUnitリポジトリにおいてブランチされているので、cvsで入手する際に"Version4"のブランチ名を指定します。

JUnitのビルド

ant一発、junit.jarが生成されるので、実行時はこれをクラスパスに含めるだけです。

アノテーションをどこで使っているか?

ぱらっと見た範囲では、org.junit.runner.internal.TestClassRunnerが核心のようです。こいつのrunメソッドがテストケースクラス個々に対応して呼ばれるようです。エラー処理や付加的な処理を除いたrunメソッドの骨格は以下のような感じです。

public void run() {
    runBeforeClasses();
    runTestMethods();
    runAfterClasses();
}

runBeforeClassesが、従来のsetUpメソッド相当の呼び出し、runAfterClassesが従来のtearDownメソッド呼び出しに相当します。

runBeforeClassesメソッドは同じくTestClassRunnerで定義されており、骨格部分は以下のようになります。

public void runBeforeClasses() {
    List<Method> beforeMethods = fTestIntrospector.getTestMethods(BeforeClass.class);
    for (Method method : beforeMethods)
        method.invoke(null);
}

BeforeClassは、アノテーション型です。


TestIntrospecotrクラスのgetTestMethodsメソッドは、引数にアノテーション型を取りまり、引数で指定されたアノテーションが付与されるメソッドを返却します。骨格部分は以下のようになります。

public List<Method> getTestMethods(Class<? extends Annotation> annotationClass) {
    List<Method> results = new ArrayList<Method>();
    for (Class eachClass : getSuperClasses(fTestClass)) {
        Method[] methods = eachClass.getDeclaredMethods();
        for (Method eachMethod : methods) {
            Annotation annotation = eachMethod.getAnnotation(annotationClass);
            if (annotation != null && isShadowed(eachMethod, results))
                results.add(eachMethod);
            }
        }
   }
   return resuls;
}