第8章 その他の Java 8 機能を理解する : 問題 12 : 繰り返し指定できるアノテーション
問題
以下のようなプログラムを実装せよ。
引数と戻り値の型はint
と想定する。
解答
JUnit の簡易版を実装せよ、ってことですな。
引数と戻り値の型がString
のTestCase
アノテーションは、本文で定義してあるので、それを流用する。
■ 単純な 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