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

1概要

この記事では、 プロパティ検査 の概念と、 vavr-test ライブラリ でのその実装について説明します。

Property based testing (PBT)は、プログラムが従うべき不変条件に関するプログラムの高水準の振る舞いを指定することを可能にします。

** 2プロパティテストとは

プロパティは、不変式と 入力値ジェネレータ の組み合わせです。生成された値ごとに、不変式は述部として扱われ、その値に対してtrueまたはfalseになるかどうかが検査されます。

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

その振る舞いのおかげで、不必要な作業をしないで条件が満たされない場合、私たちのテストは失敗します。

3 Mavenの依存関係

まず、https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22io.javaslang%22%20AND%20a%3A%22javaslang-test%にMaven依存関係を追加する必要があります22[ vavr-test ]ライブラリ:

<dependency>
    <groupId>io.vavr</groupId>
    <artifactId>jvavr-test</artifactId>
    <version>${vavr.test.version}</version>
</dependency>

<properties>
    <vavr.test.version>2.0.5</vavr.test.version>
</properties>

4プロパティベースのテストを書く

文字列のストリームを返す関数を考えてみましょう。これは、単純な規則に基づいて数字を文字列にマップする、0以上の無限のストリームです。ここでは、リンクと呼ばれる興味深いVavr機能を使用しています。/vavr-pattern-matching[パターンマッチング]:

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

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

このような方法の単体テストを書くことはエラーを起こしやすいでしょう。なぜなら、私たちはあるエッジケースを忘れる可能性が高く、基本的にすべての可能なシナリオをカバーするわけではないからです。

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

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

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

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

CheckedFunction1<Integer, Boolean> 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<Integer> multiplesOf5 = Arbitrary.integer()
  .filter(i -> i > 0)
  .filter(i -> i % 5 == 0 && i % 2 == 0);

CheckedFunction1<Integer, Boolean> mustEquals
  = i -> stringsSupplier().get(i).endsWith("DividedByTwoAndFiveWithoutRemainder");

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

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

5結論

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

我々はvavr __- test ライブラリを使ってテストを作成しました。 vavr-testを使用してプロパティベースのテストを定義するには、 Arbitrary、CheckedFunction、 、および Property クラスを使用しました。

これらすべての例とコードスニペットの実装はhttps://github.com/eugenp/tutorials/tree/master/vavr[over GitHub]で見つけることができます - これはMavenプロジェクトなので、インポートおよび実行が簡単なはずですそのまま。