GoogleはJavaプログラム用単体テストツール「JUnit」を利用する際、自社開発のテストフレームワークを利用している。社内では「JUnit 4」とこのテストフレームワークを組み合わせて利用している。2021年3月にテストフレームワークをオープンソース化しており、2022年9月には他社の開発者向けに「JUnit 5」をサポートした。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
Googleは2022年9月7日(米国時間)、Javaプログラム用単体テストツール「JUnit」に対応したオープンソースのパラメーター化テストフレームワーク「TestParameterInjector」で「JUnit 5」(Jupiter)をサポートしたと発表した。
TestParameterInjectorは、もともとGoogleが社内で使っていたものだ。同社は2021年3月に、「JUnit 4」に対応したTestParameterInjectorのオープンソース版を公開している。
それから1年以上を経て、TestParameterInjectorはGoogle社内で利用が急増しており、圧倒的な人気を持つパラメーター化テストフレームワークとなっている。
上図のグラフが示しているように、Google社内ではTestParameterInjectorを用いたパラメーター化テストが急激に増加している。理由は2つある。まず、TestParameterInjectorが通常の単体テストのパラメーター化を容易にしたことだ。次にGooglerがテスト品質向上のために、このツールをより積極的に使用するようになったことだという。
Google社内では現在、JUnit 4のみを使用しているが、社外の開発者の一部は、JUnit 5(Jupiter)に移行している。そうした開発者のために、TestParameterInjectorをJUnit 5に対応させた。
次のコードに示すように、APIは可能な限りそのまま維持されている。
// **************** JUnit4 **************** // @RunWith(TestParameterInjector.class) public class MyTest { @TestParameter boolean isDryRun; @Test public void test1(@TestParameter boolean enableFlag) { ... } @Test public void test2(@TestParameter MyEnum myEnum) { ... } enum MyEnum { VALUE_A, VALUE_B, VALUE_C } } // **************** JUnit5 (Jupiter) **************** // class MyTest { @TestParameter boolean isDryRun; @TestParameterInjectorTest void test1(@TestParameter boolean enableFlag) { // This method is run 4 times for all combinations of isDryRun and enableFlag } @TestParameterInjectorTest void test2(@TestParameter MyEnum myEnum) { // This method is run 6 times for all combinations of isDryRun and myEnum } enum MyEnum { VALUE_A, VALUE_B, VALUE_C } }
JUnit 4版とJUnit5対応版の違いは、「@RunWith」「@ExtendWith」が不要なことと、全てのテストメソッドに「@TestParameterInjectorTest」のアノテーションが必要なことだ。
TestParameterInjectorの他の機能は、次のコードのようにJUnit 5使用時も同様に動作する。
class MyTest { // **************** Defining sets of parameters **************** // @TestParameterInjectorTest @TestParameters(customName = "teenager", value = "{age: 17, expectIsAdult: false}") @TestParameters(customName = "young adult", value = "{age: 22, expectIsAdult: true}") void personIsAdult_success(int age, boolean expectIsAdult) { assertThat(personIsAdult(age)).isEqualTo(expectIsAdult); } // **************** Dynamic parameter generation **************** // @TestParameterInjectorTest void matchesAllOf_throwsOnNull( @TestParameter(valuesProvider = CharMatcherProvider.class) CharMatcher charMatcher) { assertThrows(NullPointerException.class, () -> charMatcher.matchesAllOf(null)); } private static final class CharMatcherProvider implements TestParameterValuesProvider { @Override public List<CharMatcher> provideValues() { return ImmutableList.of( CharMatcher.any(), CharMatcher.ascii(), CharMatcher.whitespace()); } } }
例えば、次のパラメーター化テストを実行するとしよう。
@Test @TestParameters("{age: 17, expectIsAdult: false}") @TestParameters("{age: 22, expectIsAdult: true}") public void withRepeatedAnnotation(int age, boolean expectIsAdult){ ... }
すると生成されるテスト名は次のようになる。
MyTest#withRepeatedAnnotation[{age: 17, expectIsAdult: false}] MyTest#withRepeatedAnnotation[{age: 22, expectIsAdult: true}]
このように小さなパラメーターセットでは問題は起きないものの、@TestParametersの数やYAML文字列内のパラメーター数が多くなると、各パラメーターセットが何を表しているのかが分かりにくくなる。
こうした場合のために、「customName」を追加するオプションが追加された。
@Test @TestParameters(customName = "teenager", value = "{age: 17, expectIsAdult: false}") @TestParameters(customName = "young adult", value = "{age: 22, expectIsAdult: true}") public void personIsAdult(int age, boolean expectIsAdult){...}
最近、TestParameterInjectorアノテーションをサポートするバージョンの「RobolectricTestRunner」が、Google社内で作成された。だが、これをオープンソース化するにはまだかなりの作業が残っている。Googleは、このバージョンのオープンソース化をいつ、どのように進めるかは、検討中だとしている。
Copyright © ITmedia, Inc. All Rights Reserved.