探索JUnit 4拡張:Runner


敏捷なトレーニングに参加する時、Junnit 4のRunnerとRuleについてコーチが言及しました.そこで、ネットで調べてみると、たくさんの話が理論的で、或いは挙げた例はあまりにも無理です.多く検索して、2編まで検索しました.とてもいい文章だと思います.
        文章の住所:http://www.blogjava.net/jiangshachina/archive/2011/12/14/366289.html
       
        JUnitを使っている間に、JUnitを少し広めてくれるかもしれません.本明細書の例は、JUnit 4が新たなAnnotationを定義し、これに応じて既存のRunnerを拡張し、新たに導入されたAnnotationを解析できるようにする.
        本論文は一例を推計して、セルテスト方法を実行する前に、自動的にセルテスト方法のためにログを印刷する.この例示会は、JUnitのために印刷するログの内容を指定するための新しいAnnotationを定義し、JUnitのデフォルトで提供されているRunnerは、BlockJUnit 4 Class Runnerを拡張して、これを認識することができるようにする.
1.Annotationを定義する
        TestLoggerは方法のAnnotationとして機能しています.ログの内容を指定する属性は一つしかありません.コードは下記の通りです.
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface TestLogger {
    public String log() default "";
}
 
2.Runnerの拡張
        JUnitは、BlockJUnit 4 Class RunnerのようないくつかのRunnerの実装を提供し、Suiteは、BlockJUnit 4 Class Runnerが単一のテストケースクラスを実行するために使用される.ロギング・ルーナーはBlockJUnit 4 Class Runnerを拡張して、その中のmethodBlock()の方法を書き込みます.新しいmethodBlockメソッドは、最初に実行されたテスト方法のTestLogガーAnnotationを取得しようとします.存在すると、指定されたログが印刷されます.各行ログは、その時点の実行時間と完全な方法名をプレフィックスとしています.このクラスのコードは以下の通りです.
public class LoggedRunner extends BlockJUnit4ClassRunner {

    private static final DateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss_SSS");

    public LoggedRunner(Class<?> klass) throws InitializationError {
        super(klass);
    }

    @Override
    protected Statement methodBlock(FrameworkMethod method) {
        Method classMethod = method.getMethod();
        TestLogger loggerAnnotation = classMethod.getAnnotation(TestLogger.class);
        if (loggerAnnotation != null) {
            StringBuilder log = new StringBuilder(format.format(new Date()));
            log.append(" ").append(classMethod.getDeclaringClass().getName())
                    .append("#").append(classMethod.getName()).append(": ")
                    .append(loggerAnnotation.log());
            System.out.println(log.toString());
        }

        return super.methodBlock(method);
    }
}
 
3.アプリケーション
        Calculatorは簡単なアプリケーションです.ここでは除算方法を定義しています.コードは以下の通りです.
public class Calculator {

    public int divide(int a, int b) {
        return a / b;
    }
}
 
4.ユニットテストプログラム
        CalculatoTestは簡単なユニットテストプログラムで、Calculatorのdivide()方法を二つの方法でユニットテストします.そのコードは以下の通りです.
@RunWith(LoggedRunner.class)
public class CalculatorTest {

    private static Calculator calculator = null;

    @BeforeClass
    public static void createCalculator() {
        calculator = new Calculator();
    }

    @Test
    @TestLogger(log = "a simple division.")
    public void simpleDivide() {
        int value = calculator.divide(8, 2);
        Assert.assertTrue(value == 4);
    }

    @Test(expected = ArithmeticException.class)
    @TestLogger(log = "divided by zero, and an ArithmeticException thrown.")
    public void dividedByZero() {
        calculator.divide(8, 0);
    }
}
        なお、CalculatoTestは、試験実行器としてLoggdeRunnerを特別指定している(@RunWith(LoggdeRunner.class).また、各ユニットのテスト方法は、simpleDivide()とdividedByZero()で、Annotation TestLoggerを使用して、そのログの内容を指定します.上記ユニットテストを行うと、以下のようなログの内容が自動的に印刷されます.
2014-09-23_23:02:33_890 com.bijian.study.CalculatorTest#simpleDivide: a simple division
2014-09-23_23:02:33_890 com.bijian.study.CalculatorTest#dividedByZero: divided by zero, and an ArithmeticException thrown.
 
5.まとめ
        BlockJUnit 4 Class Runnerの拡張により、JUnitはテスト用の動作時に余分な仕事をさせることができます.しかし、この直接的な修正は、デフォルトTest Runnerの方式では提唱されておらず、Test Ruleを使用して同じ拡張目的を達成することができる.