【Java】【Junit5】@Parametarizedによるパラメータ化テスト

2024年4月13日

@ParametarizedTestを使ったパラメータ化テスト

Junit5より@ParametarizedTestを使用することでテストメソッド単位のパラメータ化テストを簡単に実装できるようになりました。

テストメソッドへのパラメータもCSVファイルやヘルパーメソッドなど様々な方法で提供できるようになっています。本記事では@CsvSourceと@MethodSourceの使い方を紹介します。

@CsvSourceの使い方

@CsvSourceは下記の例のようにアノテーション内にCSV形式でパラメータを記述します。テストメソッドの各引数とCSVのカラムが並び順に対応します。テストメソッドのn番目の引数にはCSVのn番目のカラムの値が代入されます。

@CsvSource内には文字列でデータを記述するため、テストメソッドの引数へはキャストが発生します。キャストで対応できない型変換が必要な場合は後述の@MethodSourceを使う必要があります。

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

public class PointTableTest {


    @ParameterizedTest
    @CsvSource({
            "0, 0",
            "999, 0",
            "1000, 100",
            "1999, 100",
            "2000, 200",
            "2001, 200",
    })
    public void pointTable1Test(int paymentAmount, int expectedPoint) {

        var pointTable = new PointTable1();
        assertThat(pointTable.calculatePointsOnPurchase(paymentAmount)).isEqualTo(expectedPoint);
    }

    @ParameterizedTest
    @CsvSource({
            "0, 0",
            "999, 0",
            "1000, 100",
            "1999, 100",
            "2000, 200",
            "2001, 200",
    })
    public void pointTable2Test(int paymentAmount, int expectedPoint) {

        var pointTable = new PointTable2();
        assertThat(pointTable.calculatePointsOnPurchase(paymentAmount)).isEqualTo(expectedPoint);
    }
}

@CsvFileSourceの使い方

@CsvFileSourceを使うことでテストデータを記述したCSVファイルをパラメータのデータソースとすることができます。Spring BootでのresourcesディレクトリをルートディレクトリとしてデータソースCSVファイルを指定するにはアノテーションのresources に"/TestData.csv" のように記述します。

@CsvFileSourceも@CsvFileSourceと同様にテストメソッドの各引数とCSVのカラムが並び順に対応します。テストメソッドのn番目の引数にはCSVのn番目のカラムの値が代入されます。

また、CSVファイル内では文字列でデータを記述するため、テストメソッドの引数へはキャストが発生します。キャストで対応できない型変換が必要な場合は後述の@MethodSourceを使う必要があります。

// importは省略
public class CustomerTest {

    @CsvFileSource(resources= "/TestData.csv")
    @ParameterizedTest
    public void test_get_full_name(String firstName, String lastName, int age, String expected) {

        var customer1 = new Customer(firstName, lastName, age);
        assertThat(customer1.getFullName()).isEqualTo(expected);
    }
}

この例でのTestData.csvは以下のように作成しました。

"hoge", "foo", "18", "hoge foo"
"HOGE", "FOO", "18", "HOGE FOO"

@MethodSourceの使い方

@MethodSourceを使うことで独自に定義したメソッドをパラメータのデータソースとすることができます。

@ParametarizedTestを付与したテストメソッドのパラメータのデータソースとしたいメソッド名を@MethodSourceの引数に指定します。

データソースとなるメソッドは返り値の型がStream<Arguments>として作成します。Stream中の1つのAurgumentsインスタンスが1つのテストケースのパラメータを表しています。

テストメソッドの引数が複数あり、プリミティブ、String型以外の型の場合は@MethodSourceを使うとよいと思います。

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.math.BigDecimal;
import java.util.stream.Stream;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.params.provider.Arguments.arguments;

class PointRateTableTest {

    @ParameterizedTest
    @MethodSource("dataProvider")
    public void bronze_rank_test(CustomerRank customerRank, BigDecimal purchaseAmount, BigDecimal expected) {
        var pointTable = new PointRateTable();
        var rate1 = pointTable.getPointRateByCustomerRankAndPurchaseAmount(customerRank, purchaseAmount);
        assertThat(rate1).isEqualTo(expected);
    }

    static Stream<Arguments> dataProvider() {
        return Stream.of(
                arguments(CustomerRank.BRONZE, new BigDecimal("1"), new BigDecimal("0.01")),
                arguments(CustomerRank.BRONZE, new BigDecimal("999"), new BigDecimal("0.01")),
                arguments(CustomerRank.BRONZE, new BigDecimal("1000"), new BigDecimal("0.05")),
                arguments(CustomerRank.BRONZE, new BigDecimal("9999"), new BigDecimal("0.05")),
                arguments(CustomerRank.BRONZE, new BigDecimal("10000"), new BigDecimal("0.1")),
                arguments(CustomerRank.SILVER, new BigDecimal("1"), new BigDecimal("0.02")),
                arguments(CustomerRank.SILVER, new BigDecimal("999"), new BigDecimal("0.02")),
                arguments(CustomerRank.SILVER, new BigDecimal("1000"), new BigDecimal("0.06")),
                arguments(CustomerRank.SILVER, new BigDecimal("9999"), new BigDecimal("0.06")),
                arguments(CustomerRank.SILVER, new BigDecimal("10000"), new BigDecimal("0.11"))
        );
    }
}

参考情報

Package org.junit.jupiter.params.provider

Java

Posted by fanfanta