CUBは子供の白熊

Java SE 8 実践プログラミングの練習問題を解く

第8章 その他の Java 8 機能を理解する : 問題 12 : 繰り返し指定できるアノテーション

問題

以下のようなプログラムを実装せよ。

  1. TestCaseアノテーションを定義し
  2. そのアノテーションを持つクラスをロードして
  3. アノテーションが付いたメソッドを呼び出し
  4. メソッドが期待した値を返すかを検査する

引数と戻り値の型はintと想定する。

解答

JUnit の簡易版を実装せよ、ってことですな。

引数と戻り値の型がStringTestCaseアノテーションは、本文で定義してあるので、それを流用する。

■ 単純な Test Case

// 本アノテーションは繰り返し宣言できる
@Repeatable(TestCases.class)
public @interface TestCase {
    /** 引数 */
    int param();
    /** 想定する戻り値 */
    int expected();
}

TestCaseアノテーションの繰り返し

@Retention(RetentionPolicy.RUNTIME)  // 実行時にアノテーションを取得できるように
@Target(ElementType.METHOD)
public @interface TestCases {
    TestCase[] value();
}

このTestCaseは、テスト対象のオブジェクトの生成方法が指定されていない。
そこで、テストするメソッドは static に限定する。

TestCaseアノテーションでテストする対象

public class TestTarget {
    @TestCase(param=4, expected=24)
    @TestCase(param=1, expected= 1)
    public static int factorial(int n) {
        return n <= 1 ? 1 : n * factorial(n - 1);
    }
}

では、TestCaseアノテーションを実行して検査するコードを書いてみよう。 仕様は、以下のようにする。

  • 入力は、検査対象のクラス名
  • 戻り値が想定する戻り値と一致するときは、"OK" と表示
  • 戻り値が想定する戻り値と一致しないときは、"NG" と表示
  • 例外が発生したときは、"NG" と表示

TestCaseアノテーションを実行して検査

public static void test(String className) throws Exception {
    Class<?> clazz = Class.forName(className);
    for (Method method : clazz.getMethods()) {
        TestCases testCases = method.getAnnotation(TestCases.class);
        if (testCases == null)
            continue;
        for (TestCase testCase : testCases.value()) {
            System.out.print(
                "テストケース : 引数 = " + testCase.param() +
                ", 戻り値 = " + testCase.expected() + " : "
            );
            try {
                int ret = (Integer)method.invoke(null, testCase.param());
                if (ret == testCase.expected()) {
                    System.out.println("OK");
                } else {
                    System.out.println("NG, 戻り値 = " + ret);
                }
            } catch (Exception ex) {
                System.out.println("NG, 例外 : " + ex);
            }
        }
    }
}

TestTargetを検査したときは、以下のように出力される。

テストケース : 引数 = 4, 戻り値 = 24 : OK
テストケース : 引数 = 1, 戻り値 = 1 : OK