Vavrによるプロパティテストの例

Vavrを使用したプロパティテストの例

1. 概要

この記事では、Property Testingの概念と、vavr-testライブラリ.でのその実装について説明します。

Property based testing(PBT)を使用すると、プログラムが準拠する必要のある不変条件に関するプログラムの高レベルの動作を指定できます。

2. 特性試験とは何ですか?

プロパティは、不変条件とinput values generatorの組み合わせです。 生成された値ごとに、不変式は述語として扱われ、その値に対してtrueまたはfalseが生成されるかどうかがチェックされます。

falseを生成する値が1つあるとすぐに、プロパティは改ざんされたと言われ、チェックは中止されます。 特定の量のサンプルデータの後でプロパティを無効にできない場合、プロパティは満たされたと見なされます。

その動作のおかげで、不必要な作業を行わずに条件が満たされない場合、テストは失敗します。

3. メーベン依存

まず、Mavenの依存関係をvavr-testライブラリに追加する必要があります。


    io.vavr
    jvavr-test
    ${vavr.test.version}



    2.0.5

4. プロパティベースのテストの作成

文字列のストリームを返す関数について考えてみましょう。 単純なルールに基づいて数字を文字列にマッピングする0の無限ストリームです。 ここでは、Pattern Matchingと呼ばれる興味深いVavr機能を使用しています。

private static Predicate divisibleByTwo = i -> i % 2 == 0;
private static Predicate divisibleByFive = i -> i % 5 == 0;

private Stream stringsSupplier() {
    return Stream.from(0).map(i -> Match(i).of(
      Case($(divisibleByFive.and(divisibleByTwo)), "DividedByTwoAndFiveWithoutRemainder"),
      Case($(divisibleByFive), "DividedByFiveWithoutRemainder"),
      Case($(divisibleByTwo), "DividedByTwoWithoutRemainder"),
      Case($(), "")));
}

このようなメソッドの単体テストを作成すると、エラーが発生しやすくなります。これは、エッジケースを忘れて、基本的にすべての可能なシナリオをカバーできない可能性が高いためです。

幸いなことに、すべてのエッジケースをカバーするプロパティベースのテストを作成できます。 最初に、テストの入力となる数値の種類を定義する必要があります。

Arbitrary multiplesOf2 = Arbitrary.integer()
  .filter(i -> i > 0)
  .filter(i -> i % 2 == 0 && i % 5 != 0);

入力数は2つの条件を満たしている必要があることを指定しました。0より大きくする必要があり、5でなく2で割り切れる必要があります。

次に、テストされた関数が指定された引数に対して適切な値を返すかどうかをチェックする条件を定義する必要があります。

CheckedFunction1 mustEquals
  = i -> stringsSupplier().get(i).equals("DividedByTwoWithoutRemainder");

プロパティベースのテストを開始するには、Propertyクラスを使用する必要があります。

CheckResult result = Property
  .def("Every second element must equal to DividedByTwoWithoutRemainder")
  .forAll(multiplesOf2)
  .suchThat(mustEquals)
  .check(10_000, 100);

result.assertIsSatisfied();

2の倍数であるすべての任意の整数について、mustEquals述語が満たされる必要があることを指定しています。 check()メソッドは、生成された入力のサイズと、このテストが実行される回数を取ります。

stringsSupplier()関数が、余りなしで2と5で割り切れるすべての入力番号に対してDividedByTwoAndFiveWithoutRemainder stringを返すかどうかを検証する別のテストをすばやく作成できます。

ArbitraryサプライヤとCheckedFunctionを変更する必要があります。

Arbitrary multiplesOf5 = Arbitrary.integer()
  .filter(i -> i > 0)
  .filter(i -> i % 5 == 0 && i % 2 == 0);

CheckedFunction1 mustEquals
  = i -> stringsSupplier().get(i).endsWith("DividedByTwoAndFiveWithoutRemainder");

その後、プロパティベースのテストを1,000回繰り返し実行できます。

Property.def("Every fifth element must equal to DividedByTwoAndFiveWithoutRemainder")
  .forAll(multiplesOf5)
  .suchThat(mustEquals)
  .check(10_000, 1_000)
  .assertIsSatisfied();

5. 結論

この簡単な記事では、プロパティベースのテストの概念について説明しました。

vavr-testライブラリを使用してテストを作成しました。 Arbitrary, CheckedFunction,クラスとPropertyクラスを使用して、vavr-test.を使用したプロパティベースのテストを定義しました。

これらすべての例とコードスニペットの実装はover on GitHubにあります。これはMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。