0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ひとりJUnitAdvent Calendar 2022

Day 5

JUnit5の@ParameterizedTestで行われる引数の型変換

Posted at

はじめに

ひとりJUnitアドベントカレンダー5日目の記事です。
5日目にして息切れしてきました。ひとりカレンダーしてる人すごい。時間がアホほど溶ける。

@ParameterizedTestで受け渡される引数の型

この記事が載るアドベントカレンダーの2日目〜4日目までで、
@ParameterizedTestのさまざまな使い方、特に引数の渡し方を見てきました。

  @ParameterizedTest
  @ValueSource(ints = {0, 1, 100, 1000})
  void test(int number) {
    int actual = hogeService.roundDown(number);
    assertThat(actual, is(0));
  }

上記の例で言えば、@ValueSourceで指定している4つの数値が引数numberに設定され、
1つのテストコードで4回分のテストが実行されます。

@ValueSourceintsと指定して、引数でもintを受け取っていますが
必ずしもSource側で指定されている型のみしか受け取れないわけではありません。
Stringを渡した場合、JUnitが提供する仕組みにより別の型として受け取ることができます。

基本的な型変換

まずはenumです。

  @AllArgsConstructor
  @ToString
  private enum Nen {

    TEN("纏"),
    ZETSU("絶"),
    REN("練"),
    HATSU("発");

    private String kanji;
  }

  @ParameterizedTest
  @ValueSource(strings = {"TEN", "ZETSU", "REN", "HATSU"})
  void test(Nen nen) {
    System.out.println(nen);
  }

定義名(要するにenumのname()の戻り値)を指定し、
引数の型としてenumのクラス名を指定すると、その定義を受け取ることができます。

実行結果は以下の通り。しっかりenumとして受け取れています。
image.png

また、プリミティブ型も変換できます。

  @ParameterizedTest
  @ValueSource(strings = {"true", "false"})
  void test(boolean isFoo) {
    System.out.println(isFoo);
  }

が、以下のように書けばよいだけなので、こちらを使うことはほぼないでしょう。

  @ParameterizedTest
  @ValueSource(booleans = {true, false})
  void test(boolean isFoo) {
    System.out.println(isFoo);
  }

以下のようなたまに使ったり使わなかったりするクラスにも変換できます。

  @ParameterizedTest
  @ValueSource(strings = {"2022-12-05", "2023-01-05"})
  void test(LocalDate localDate) {
    System.out.println(localDate);
  }

  @ParameterizedTest
  @ValueSource(strings = "https://qiita.com/advent-calendar/2022")
  void test(URI uri) {
    System.out.println(uri);
  }

  @ParameterizedTest
  @ValueSource(strings = {"en", "ja"})
  void test(Locale locale) {
    System.out.println(locale);
  }

全ラインナップはこちら。

staticファクトリメソッドによる型変換

staticファクトリメソッドとは、そのクラスのインスタンスを返すstaticメソッドのことです。
例えば以下のようなもの。

  @AllArgsConstructor
  @ToString
  public class Student {
    private String name;

    public static Student of(String name) {
      return new Student(name);
    }
  }
  
  public void hoge() {
    Student student = Student.of("John");
  }

Javaのパッケージで言うと、LocalDateTime#ofBoolean#valueOfなどがそうです。
メソッド名はofvalueOfの他、fromgetInstance等もよく見られます。

JUnit5では、Stringの引数一件を受け取るstaticファクトリメソッドがある場合
自動的にそのメソッドを使って型変換を行うことができます。

  @AllArgsConstructor
  @ToString
  public class Student {
    private String name;

    public static Student of(String name) {
      return new Student(name);
    }
  }

  @ParameterizedTest
  @ValueSource(strings = {"Bob", "Tom"})
  void test(Student student) {
    System.out.println(student);
  }

じゃあStringを受け取るstaticファクトリメソッドが二つあったらどうなるの?ということで
以下のテストを実行してみました。

  @ToString
  @Setter
  @NoArgsConstructor
  public class Student {
    private String name;

    public Student(String name) {
      System.out.println("constructor");
      this.name = name;
    }

    public static Student of(String name) {
      Student student = new Student();
      student.setName(name);
      System.out.println("of");
      return student;
    }

    public static Student valueOf(String name) {
      Student student = new Student();
      student.setName(name);
      System.out.println("valueOf");
      return student;
    }
  }

  @ParameterizedTest
  @ValueSource(strings = {"Bob", "Tom"})
  void test(Student student) {
    System.out.println(student);
  }

引数ありコンストラクタとstaticファクトリメソッド二種にsysoutを仕込んでいます。
さて、出力されるのはofか、それともvalueOfなのか、どちらかというと・・・

実はconstructorです。

というのも、staticファクトリメソッドが2種類あるとどちらも無視されるという仕様があり
またstaticファクトリメソッドが無くても、引数がString一つのコンストラクタがあれば
そちらを元に暗黙の型変換が行われるようになっているようなのです。

整理するとこんな感じです。
image.png
staticファクトリメソッドの方がコンストラクタよりも優先度は高い。
ただ、メソッドが2件以上あると無視される。ということですね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?