JUnit4.4 - その5 拡張方法

== 2011/06/15 追記 ==
JUnit4.5以降の拡張方法を書きました。

JUnit4.5以降の拡張方法 - ひたすらプログラミング日記

=========



JUnitを拡張して、独自の振る舞い等をテスト中に追加させたい場合は下記のような処理が必要になります。

  • org.junit.runner.Runnerを継承し、独自の振る舞いを定義したクラスを作成する。
  • テストクラスに@Runwith(XXX.class)を定義する。

こんな感じ

/** JUnit4ClassRunnerはJUnitに初めからあるRunnerクラスのサブクラス */
public class FooRunner extends JUnit4ClassRunner{

    public FooRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }
    
    //拡張したいメソッドをオーバーライド
}

テストクラス

@RunWith(FooRunner.class)
public class FooTest extends ParentFooTest{

/** テストを記述 */

}

んで、さらにここからちょこっといじると「@Beforeに記述するほど全てのメソッドでは必要がないけれどテストクラス内にて数箇所のテストで共通の事前処理がしたい!」って場合の対応もでるっぽいです(というか自分的にはこれがしたかったんでJUnitをいじりはじめましたw)

準備するのは下記

・JUnit4ClassRunnerのサブクラス
・TestMethodクラスのサブクラス
・独自のAnnotation

こんな感じ

public class FooRunner extends JUnit4ClassRunner{

    public FooRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }
    
    @Override
    protected TestMethod wrapMethod(Method method) {
        return new FooMethodRunner(method, getTestClass());
    }
}
public class FooMethodRunner extends TestMethod{

    private boolean fAnnotation;
    
    public FooMethodRunner(Method method, TestClass testClass) {
        super(method, testClass);
        fAnnotation = method.getAnnotation(FooAnnotation.class) != null;
    }

    @Override
    public void invoke(Object test) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
        if(fAnnotation) System.out.println("Annotation exists");
        super.invoke(test);
    }
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface FooAnnotation {
}

んで、実際のテストクラス

@RunWith(FooRunner.class)
public class FooTest extends ParentFooTest{

    @Before
    public void before(){
        System.out.println("--------");
    }

    @Test
    public void testA(){
        System.out.println("testA");
    }

    @FooAnnotation
    @Test
    public void testB() {
        System.out.println("testB");
    }
}


上記を実行した結果は

.--------
testA
.--------
Annotation exists
testB

と、こんな感じになります。これをさらに拡張してDBUnit等とからめることでDBへのアクセスが発生するメソッドとそうでないメソッドが同一クラス内に存在するドメインモデル等のテストがしやすくなるかなと。さらに@Checkみたいなアノテーションが存在すれば更新処理の結果検証もExcelXMLYAML等から自動でしてくれるみたいなのも比較的簡単につくれるんじゃないかなぁ。一番の問題はJUnitの拡張ポイントを間違えていないかどうかwww。突っ込み大歓迎です。