Lambda Behaveの紹介

ラムダ動作の概要

1. 概要

この記事では、Lambda Behaveと呼ばれる新しいJavaベースのテストフレームワークについて説明します。

名前が示すように、このテストフレームワークはJava 8 Lambdasで動​​作するように設計されています。 さらに、この記事では、仕様を調べて、それぞれの例を示します。

含める必要があるMavenの依存関係は次のとおりです。


    com.insightfullogic
    lambda-behave
    0.4

最新バージョンはhereで見つけることができます。

2. 基本

フレームワークの目標の1つは、読みやすくすることです。 構文は、わずかな単語ではなく完全な文を使用してテストケースを記述することを推奨します。

パラメータ化されたテストを活用でき、テストケースを事前定義された値にバインドしたくない場合は、ランダムなパラメータを生成できます。

3. Lambdaの動作テストの実装

すべての仕様スイートはSuite.describe.で始まります。この時点で、仕様を宣言するためのいくつかの組み込みメソッドがあります。 したがって、SuiteはJUnitテストクラスのようなものであり、仕様はJUnitの@Testで注釈が付けられたメソッドのようなものです。

テストを説明するために、should().を使用します。同様に、期待ラムダパラメーターに“expect”,という名前を付けると、テストから期待される結果をexpect.that()で表すことができます。

仕様の前後でデータをセットアップまたは破棄する場合は、it.isSetupWith()it.isConcludedWith().を使用できます。同様に、Suiteの前後で何かを行う場合は次のようになります。 it.initiatizesWith()it.completesWith().を使用します

Calculatorクラスの簡単なテスト仕様の例を見てみましょう。

public class Calculator {

    public int add() {
        return this.x + this.y;
    }

    public int divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException();
        }
        return a / b;
    }
}

Suite.describeから始めて、Calculator.を初期化するコードを追加します

次に、仕様を記述してadd()メソッドをテストします。

{
    Suite.describe("Lambda behave example tests", it -> {
        it.isSetupWith(() -> {
            calculator = new Calculator(1, 2);
        });

        it.should("Add the given numbers", expect -> {
            expect.that(calculator.add()).is(3);
        });
}

ここでは、読みやすくするために変数に“it”“expect”という名前を付けました。 これらはラムダパラメーター名であるため、これらを任意の名前に置き換えることができます。

should()の最初の引数は、このテストで何をチェックすべきか、平易な英語の使用を説明しています。 2番目の引数はラムダです。これは、add()メソッドが3を返す必要があるという期待を示しています。

0で除算するための別のテストケースを追加し、例外が発生するかどうかを確認しましょう。

it.should("Throw an exception if divide by 0", expect -> {
    expect.exception(ArithmeticException.class, () -> {
        calculator.divide(1, 0);
    });
});

この場合、例外が発生することが予想されるため、expect.exception()を記述し、その中に例外をスローするコードを記述します。

テキストの説明は、仕様ごとに一意である必要があることに注意してください。

4. データ駆動型仕様

このフレームワークにより、仕様レベルでのテストのパラメーター化が可能になります。

例を作成するために、Calculatorクラスにメソッドを追加しましょう。

public int add(int a, int b) {
    return a + b;
}

そのためのデータ駆動型テストを書いてみましょう。

it.uses(2, 3, 5)
  .and(23, 10, 33)
  .toShow("%d + %d = %d", (expect, a, b, c) -> {
    expect.that(calculator.add(a, b)).is(c);
});

uses()メソッドは、さまざまな列数で入力データを指定するために使用されます。 最初の2つの引数はadd()関数パラメーターであり、3番目の引数は期待される結果です。 これらのパラメーターは、テストで示されているように、説明でも使用できます。

toShow()は、パラメーターを使用したテストの説明に使用されます–次の出力があります。

0: 2 + 3 = 5 (seed: 42562700892554)(Lambda behave example tests)
1: 23 + 10 = 33 (seed: 42562700892554)(Lambda behave example tests)

5. 生成された仕様–プロパティベースのテスト

通常、単体テストを作成するときは、システムに当てはまるより広範なプロパティに焦点を当てたいと思います。

たとえば、String反転関数をテストする場合、特定のStringを2回反転すると、元のString.になることを確認できます。

Property-Based testing focuses on the generic property without hard-coding specific test parameters.ランダムに生成されたテストケースを使用してこれを実現できます。

この戦略は、データ駆動型仕様の使用に似ていますが、データのテーブルを指定する代わりに、生成するテストケースの数を指定します。

したがって、Stringの反転プロパティベースのテストは次のようになります。

it.requires(2)
  .example(Generator.asciiStrings())
  .toShow("Reversing a String twice returns the original String",
    (expect, str) -> {
        String same = new StringBuilder(str)
          .reverse().reverse().toString();
        expect.that(same).isEqualTo(str);
   });

_ indicated the number of required test cases using the _requires()メソッドがあります。 example()句を使用して、必要なオブジェクトのタイプと方法を示します。

この仕様の出力は次のとおりです。

0: Reversing a String twice returns the original String(ljL+qz2)
  (seed: 42562700892554)(Lambda behave example tests)
1: Reversing a String twice returns the original String(g)
  (seed: 42562700892554)(Lambda behave example tests)

5.1. 決定論的テストケースの生成

自動生成されたテストケースを使用すると、テストの失敗を分離することが非常に難しくなります。 たとえば、if our functionality fails once in 1000 times, a specification that auto-generates just 10 cases, will have to be run over and over to observe the error.

そのため、以前に失敗したケースを含め、テストを決定論的に再実行する機能が必要です。

Lambda Behaveはこの問題に対処できます。 前のテストケースの出力に示すように、テストケースのランダムセットを生成するために使用されたシードを出力します。 したがって、何かが失敗した場合、we can use the seed to re-create previously generated test cases.

テストケースの出力を見て、シードを特定できます:(seed: 42562700892554)。 ここで、同じテストセットを再度生成するために、SourceGeneratorを使用できます。

SourceGeneratorには、引数としてシードのみを受け取るdeterministicNumbers()メソッドが含まれています。

 it.requires(2)
   .withSource(SourceGenerator.deterministicNumbers(42562700892554L))
   .example(Generator.asciiStrings())
   .toShow("Reversing a String twice returns the original String",
     (expect, str) -> {
       String same = new StringBuilder(str).reverse()
         .reverse()
         .toString();
       expect.that(same).isEqualTo(str);
});

このテストを実行すると、前に見たのと同じ出力が得られます。

6. 結論

この記事では、Java 8ラムダ式を使用して、Lambda Behaveと呼ばれる新しい流testingなテストフレームワークで単体テストを作成する方法を説明しました。

いつものように、これらの例のコードはover on GitHubにあります。