1概要


JUnit

やhttp://testng.org[TestNG]のようなテストランナーフレームワークはいくつかの基本的なアサーションメソッド(

assertTrue



assertNotNull

など)を提供します。

それからhttp://hamcrest.org/[Hamcrest]、http://joel-costigliola.github.io/assertj/[AssertJ]、https://github.com/google/truth[Truthのようなアサーションフレームワークがあります。]は、流暢でリッチなアサーションメソッドに、通常

“assertThat”

で始まる名前を付けます。


  • JSpec

    は、他のフレームワークとは少し異なる方法ではありますが、私たちが自然言語で仕様を書く方法により近い流暢なアサーションを書くことを可能にするもう1つのフレームワークです。

この記事では、JSpecの使い方を学びます。仕様を記述するために必要な方法と、テストに失敗した場合に表示されるメッセージについて説明します。


2 Mavenの依存関係

JSpecを含む

javalite-common

依存関係をインポートしましょう。

<dependency>
    <groupId>org.javalite</groupId>
    <artifactId>javalite-common</artifactId>
    <version>1.4.13</version>
</dependency>

最新版については、https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.javalite%22%20AND%20a%3A%22javalite-common%22中央リポジトリ]。


3アサーションスタイルの比較

規則に基づいて主張する典型的な方法の代わりに、振る舞いの仕様を書くだけです。 JUnit、AssertJ、およびJSpecで同等性を主張するための簡単な例を見てみましょう。

JUnitでは、次のように書きます。

assertEquals(1 + 1, 2);

そしてAssertJでは、次のように書きます。

assertThat(1 + 1).isEqualTo(2);

JSpecでも同じテストを書く方法は次のとおりです。

$(1 + 1).shouldEqual(2);

JSpecは流暢なアサーションフレームワークと同じスタイルを使用しますが、先頭の

assert

/

assertThat

キーワードを省略し、代わりに

should

を使用します。

このようにアサーションを書くことで、実際の仕様を表現することが簡単になり、TDDとBDDの概念が促進されます。

この例が、私たちの自然な仕様書に非常に近いかを見てください。

String message = "Welcome to JSpec demo";
the(message).shouldNotBe("empty");
the(message).shouldContain("JSpec");


4仕様の構造

  • 仕様記述は2つの部分から成ります:** 期待作成者と期待メソッド。


4.1. 期待クリエーター

期待値作成者は、静的にインポートされた次のメソッドの1つを使用して

Expectation

オブジェクトを生成します。

a()



the()



it()



$():

$(1 + 2).shouldEqual(3);
a(1 + 2).shouldEqual(3);
the(1 + 2).shouldEqual(3);
it(1 + 2).shouldEqual(3);

これらの方法はすべて基本的に同じです。これらはすべて、仕様を表現するためのさまざまな方法を提供するためだけに存在します。

唯一の違いは


it()

メソッドが型保証されていることです。

同じ型のオブジェクトのみ比較できます

it(1 + 2).shouldEqual("3");


it()

を使用して異なるタイプのオブジェクトを比較すると、コンパイルエラーが発生します。


4.2. 期待方法

仕様ステートメントの2番目の部分は期待メソッドです。これは

shouldEqual



shouldContain

のように

必要な仕様について

伝えます。

テストが失敗すると、

javalite.test.jspec.TestException

型の例外が表現豊かなメッセージを表示します。

次のセクションでこれらのエラーメッセージの例を見ていきます。


5組み込みの期待

JSpecはいくつかの種類の期待メソッドを提供します。 JSpecがテストの失敗時に生成する失敗メッセージを示すそれぞれのシナリオを含めて、それらを見てみましょう。


5.1. 平等期待値



shouldEqual()、shouldBeEqual()、shouldNotBeEqual()

これらは、

java.lang.Object.equals()

メソッドを使って等しいかどうかをチェックすることで、2つのオブジェクトが等しくないことを指定します。

$(1 + 2).shouldEqual(3);

  • **

$(1 + 2).shouldEqual(4);

次のようなメッセージが表示されます。

Test object:java.lang.Integer == (3)
and expected java.lang.Integer == (4)
are not equal, but they should be.


5.2. ブールプロパティの期待値



shouldHave()、shouldNotHave()

これらのメソッドを使用して、オブジェクトの名前付き

boolean

プロパティが

true

を返さないようにするかどうかを指定します。

Cage cage = new Cage();
cage.put(tomCat, boltDog);
the(cage).shouldHave("animals");

これには

Cage

クラスにシグネチャを持つメソッドを含める必要があります。

boolean hasAnimals() {...}

  • **

the(cage).shouldNotHave("animals");

次のようなメッセージが表示されます。

Method: hasAnimals should return false, but returned true



shouldBe()、shouldNotBe()

これらを使用して、テスト対象のオブジェクトが何かであるべきでないことを指定します。

the(cage).shouldNotBe("empty");

これには、

Cage

クラスに、シグニチャ

“ boolean isEmpty()” .

を持つメソッドを含める必要があります。

  • **

the(cage).shouldBe("empty");

次のようなメッセージが表示されます。

Method: isEmpty should return true, but returned false


5.3. タイプ期待値



shouldBeType()、shouldBeA()

これらのメソッドを使って、オブジェクトが特定の型であることを指定できます。

cage.put(boltDog);
Animal releasedAnimal = cage.release(boltDog);
the(releasedAnimal).shouldBeA(Dog.class);

  • **

the(releasedAnimal).shouldBeA(Cat.class);

次のようなメッセージが表示されます。

class com.baeldung.jspec.Dog is not class com.baeldung.jspec.Cat


5.4. NULL可能性への期待



shouldBeNull()、shouldNotBeNull()

これらを使用して、テスト対象のオブジェクトを

null

にする/しないことを指定します。

cage.put(boltDog);
Animal releasedAnimal = cage.release(dogY);
the(releasedAnimal).shouldBeNull();

  • **

the(releasedAnimal).shouldNotBeNull();

次のようなメッセージが表示されます。

Object is null, while it is not expected


5.5. 参考期待



shouldBeTheSameAs()、shouldNotBeTheSameAs()

これらのメソッドは、オブジェクトの参照が期待されたものと同じであることを指定するために使用されます。

Dog firstDog = new Dog("Rex");
Dog secondDog = new Dog("Rex");
$(firstDog).shouldEqual(secondDog);
$(firstDog).shouldNotBeTheSameAs(secondDog);

  • **

$(firstDog).shouldBeTheSameAs(secondDog);

次のようなメッセージが表示されます。

references are not the same, but they should be

** 5.6. コレクションと文字列の内容



shouldContain()、shouldNotContain()


テスト済みの

Collection

または

Map

に特定の要素を含めるべきでないことを指定します。

cage.put(tomCat, felixCat);
the(cage.getAnimals()).shouldContain(tomCat);
the(cage.getAnimals()).shouldNotContain(boltDog);

  • **

the(animals).shouldContain(boltDog);

次のようなメッセージが表示されます。

tested value does not contain expected value: Dog[name=Bolt]----

** これらのメソッドを使用して、__String__に特定の部分文字列を含めるべきでないことを指定することもできます。

[source,java,gutter:,true]

$(“Welcome to JSpec demo”).shouldContain(“JSpec”);

奇妙に思えるかもしれませんが、この動作を他のオブジェクト型に拡張することができます。それらは__toString()__メソッドを使用して比較されます。

[source,java,gutter:,true]

cage.put(tomCat, felixCat);
the(cage).shouldContain(tomCat);
the(cage).shouldNotContain(boltDog);

明確にするために、__Cat__オブジェクト__tomCat__の__toString()__メソッドは次のようになります。

[source,text,gutter:,false]

Cat[name=Tom]—-

これは、

cage

オブジェクトの

toString()

出力のサブストリングです。

Cage[animals=[Cat[name=Tom], Cat[name=Felix]]]----

===  **  6. カスタム期待**

組み込みの期待に加えて、JSpecではカスタムの期待を書くことができます。

====  **  6.1. 違いへの期待**

__DifferenceExpectation__を記述して、コードを実行したときの戻り値が特定の値と等しくならないように指定できます。

この単純な例では、操作(2 3)によって結果(4)が得られないことを確認しています。

[source,java,gutter:,true]

expect(new DifferenceExpectation<Integer>(4) {
@Override
public Integer exec() {
return 2 + 3;
}
});

また、コードを実行すると、変数やメソッドの状態や値が確実に変更されるようにするためにも使用できます。

たとえば、2匹の動物を含む__Cage__から動物を解放するとき、サイズは異なるはずです。

[source,java,gutter:,true]

cage.put(tomCat, boltDog);
expect(new DifferenceExpectation<Integer>(cage.size()) {
@Override
public Integer exec() {
cage.release(tomCat);
return cage.size();
}
});

** **

ここでは、__Cage__内に存在しない動物を解放しようとしています。

[source,java,gutter:,true]

cage.release(felixCat);

サイズは変更されません。次のようなメッセージが表示されます。

[source,text,gutter:,false]

Objects: ‘2’ and ‘2’ are equal, but they should not be

====  **  6.2. 例外への期待**

テストされたコードが__Exception__をスローするように指定するために__ExceptionExpectation__を記述できます。

予想される例外の型をコンストラクタに渡して、それをジェネリック型として渡します。

[source,java,gutter:,true]

expect(new ExceptionExpectation<ArithmeticException>(ArithmeticException.class) {
@Override
public void exec() throws ArithmeticException {
System.out.println(1/0);
}
});

** **

[source,java,gutter:,true]

System.out.println(1/1);

この行は例外にはならないので、実行すると次のメッセージが表示されます。

[source,text,gutter:,true]

Expected exception: class java.lang.ArithmeticException, but instead got nothing

** **

[source,java,gutter:,true]

Integer.parseInt(“x”);

これは予想される例外とは異なる例外になります。

[source,text,gutter:,false]

class java.lang.ArithmeticException,
but instead got: java.lang.NumberFormatException: For input string: “x”

===  **  7. 結論**

他の流暢なアサーションフレームワークは、コレクションアサーション、例外アサーション、およびJava 8統合のためのより優れたメソッドを提供しますが、JSpecは仕様の形式でアサーションを書くための独自の方法を提供します。

それは自然言語のような私達の主張を書くことを可能にする簡単なAPIを持ち、そしてそれは記述的なテスト失敗メッセージを提供します。

これらすべての例の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/testing-modules/testing[GitHubでの使用] - パッケージ__com.baeldung.jspec__にあります。