JUnit5 @ParameterizedTest


テストコードを記述する際には、論理が同じで入力パラメータが異なるテストケースのみを記述する必要があることがあります.コードは重複していますが、各ケースを検証する必要があるため、テストコードを記述しないわけにはいきません.
より簡潔なコード記述方法があるかどうかを考慮すると,Junit 5は@ParameterizedTestを提供していることが分かった.

@ParameterizedTest


@ParameterizedTestは、1つのテストを複数回実行する必要があります.

@ParameterizedTestの適用方法

  • メソッドの上に@ParameterizedTestを指定します.
  • 方法のパラメータに従って、@ValueSourceを用いて順序配列を説明する.(短い、バイト、int、long、float、double、char、String、Classを指定可能)
  • 譲渡された価格のタイプをメソッドのパラメータとして書きます.
  • import org.junit.jupiter.api.extension.ExtendWith;
    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.ValueSource;
    import org.mockito.junit.jupiter.MockitoExtension;
    
    @ExtendWith(MockitoExtension.class)
    public class TestControllerTest {
    
      @ParameterizedTest
      @ValueSource(strings = {"test1", "test2", "test3"})
      void test(String value) {
        System.out.println(value);
      }
    }
    このテストコードの実行結果は次のとおりです.

    ただし、この方法は1つのパラメータを渡す場合にのみ使用でき、2つ以上のパラメータを渡すことはできません.

    @MethodSource

    @MethodSourceを使用して、2つ以上のパラメータを受信することもできる.

    import java.util.stream.Stream;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.Arguments;
    import org.junit.jupiter.params.provider.MethodSource;
    import org.mockito.junit.jupiter.MockitoExtension;
    
    @ExtendWith(MockitoExtension.class)
    public class TestControllerTest {
    
      // test method
      @ParameterizedTest
      @MethodSource("provideKeyAndValue")
      void test(Integer key, String value) {
        System.out.println(key + " " + value);
      }
    
      //source method
      private static Stream<Arguments> provideKeyAndValue() {
        return Stream.of(
            Arguments.of(1, "value1"),
            Arguments.of(2, "value2"),
            Arguments.of(3, "value3")
        );
      }
    }
    しかし、それを使用するためには、source法は静的でなければならない.
    ただし、同じテスト・インスタンスを結合すると、内部classが使用され、内部classはstatic methodを宣言できないことが多い.
    import java.util.stream.Stream;
    import org.junit.jupiter.api.Nested;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.Arguments;
    import org.junit.jupiter.params.provider.MethodSource;
    import org.mockito.junit.jupiter.MockitoExtension;
    
    @ExtendWith(MockitoExtension.class)
    public class TestControllerTest {
    
      @Nested
      public class NestedTestControllerTest {
    
        @ParameterizedTest
        @MethodSource("provideKeyAndValue")
        public void test(Integer key, String value) {
          System.out.println(key + " " + value);
        }
        
        // 에러 발생!
        private static Stream<Arguments> provideKeyAndValue() {
          return Stream.of(
              Arguments.of(1, "value1"),
              Arguments.of(2, "value2"),
              Arguments.of(3, "value3")
          );
        }
      }
    }
    不可能だという意味だ...この場合は@TestInstanceが使用可能であり、これから@TestInstanceについて知ることになる.

    @TestInstance


    @TestInstanceは、テストインスタンスのライフサイクルを設定します.
  • Lifecycle.PER METHOD(Default):テスト関数ごとにインスタンスを生成します.
  • Lifecycle.PER CLASS:テストクラスごとにインスタンスを生成します.
  • import java.util.stream.Stream;
    import org.junit.jupiter.api.Nested;
    import org.junit.jupiter.api.TestInstance;
    import org.junit.jupiter.api.TestInstance.Lifecycle;
    import org.junit.jupiter.api.extension.ExtendWith;
    import org.junit.jupiter.params.ParameterizedTest;
    import org.junit.jupiter.params.provider.Arguments;
    import org.junit.jupiter.params.provider.MethodSource;
    import org.mockito.junit.jupiter.MockitoExtension;
    
    @ExtendWith(MockitoExtension.class)
    public class TestControllerTest {
    
      @Nested
      @TestInstance(Lifecycle.PER_CLASS)
      public class NestedTestControllerTest {
    
        @ParameterizedTest
        @MethodSource("provideKeyAndValue")
        public void test(Integer key, String value) {
          System.out.println(key + " " + value);
        }
    
        private Stream<Arguments> provideKeyAndValue() {
          return Stream.of(
              Arguments.of(1, "value1"),
              Arguments.of(2, "value2"),
              Arguments.of(3, "value3")
          );
        }
      }
    }
    こうして@TestInstanceをLifecycleにPER CLASSに設定すると、同じテスト・インスタンスですべてのテスト・メソッドを実行でき、provideKeyAndValue()を静的に設定することなく@MethodSourceを使用できます.
    実際、私は上記のようにUnit Testを書くことができるかどうか分かりませんが、これは私が接触したことのない言語を使って、それを理解したからです.