mike-neckのブログ

Java or Groovy or Swift or Golang

JUnit入門(4) - TestFactoryとDynamicTest - JUnit5におけるパラメタライズドテスト実現法

前回の続き

@TestFactory

@TestFactory はJUnit4における Theories ランナーを用いたテストパラメーターをいろいろと組み合わせるテストを実現するために用いる。

@TestFactory を付与したメソッドは次のいずれかを返すメソッドを実装する必要がある。

  • Iterable<DynamicTest>
  • Iterator<DynamicTest>
  • Stream<DynamicTest>

DynamicTest はテストの名前とテストを持つクラスで、 DynamicTest#dynamicTest(String, Executable) から作ることができる。DynamicTestインスタンス一つにつきテスト1つとしてカウントされる。なお、javadocを読むかぎり @Test を付与したテストとは違い、 DynamicTest の実行の前後に @BeforeEach@AfterEach は実行されない。

サンプルコード
public class DynamicTestSample {

  @TestFactory
  Iterable<DynamicTest> dynamicTestIterable() {
    return Arrays.asList(
            dynamicTest("1 + 2 = 3", () -> assertEquals(3, 1 + 2))
            , dynamicTest("1 - 2 = -1", () -> assertEquals(-1, 1 - 2))
    );
  }

  @TestFactory
  Stream<DynamicTest> dynamicTestStream() {
    return Stream.of(
            new ThreeInts(1, 2, 3)
            , new ThreeInts(1, -2, -1)
    ).map(t -> dynamicTest(t.getTitle(), t.getTest()));
  }

  static class ThreeInts {
    final int left;
    final int right;
    final int result;

    ThreeInts(int left, int right, int result) {
      this.left = left;
      this.right = right;
      this.result = result;
    }

    String getTitle() {
      final String c = right < 0 ? "%d - %d = %d" : "%d + %d = %d";
      return String.format(c, left, Math.abs(right), result);
    }

    Executable getTest() {
      return () -> assertEquals(result, left + right);
    }
  }
}
実行結果
[         4 containers found      ]
[         0 containers skipped    ]
[         4 containers started    ]
[         0 containers aborted    ]
[         4 containers successful ]
[         0 containers failed     ]
[         4 tests found           ]
[         0 tests skipped         ]
[         4 tests started         ]
[         0 tests aborted         ]
[         4 tests successful      ]
[         0 tests failed          ]

@TestFactory のメソッドは2つだが、それぞれが2つずつテストを返して合計4つのテストが実行されている。


JUnit4で Theories ランナーで @DataPoints でデータを作っていた部分が、 DynamicTest 列の生成に置き換わり、 @Theory で行っていたテストそのものが DynamicTest に渡す Executable に置き換わったと考えるとわかりやすいかもしれません。


参考

github.com


続く