Iterableに特定のプロパティを持つ要素が含まれていることをアサートするにはどうすればよいですか?


103

このシグネチャでメソッドを単体テストしたいとします:

List<MyItem> getMyItems();

を介してアクセスされるMyItem多くのプロパティを持つPojoであると想定し"name"ますgetName()

私が確認する必要があるのは、、List<MyItem>またはany Iterableに2つのMyItemインスタンスが含まれ"name"ていることです。そのプロパティには値"foo"とがあります"bar"。他のプロパティが一致しない場合、このテストの目的は特に気にしません。名前が一致すれば、テストは成功です。

できればワンライナーにしたいです。これが私がやりたいことの一種の「疑似構文」です。

assert(listEntriesMatchInAnyOrder(myClass.getMyItems(), property("name"), new String[]{"foo", "bar"});

ハムクレストはこの種のものに良いでしょうか?もしそうなら、正確に上記の私の擬似構文のハムクレストバージョンは何でしょうか?

回答:


125

私を正しい方向に向けてくれた@Razvanに感謝します。私はそれを1行で取得することができ、Hamcrest 1.3のインポートをうまく探し出しました。

インポート:

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;

コード:

assertThat( myClass.getMyItems(), contains(
    hasProperty("name", is("foo")), 
    hasProperty("name", is("bar"))
));

49

試してください:

assertThat(myClass.getMyItems(),
                          hasItem(hasProperty("YourProperty", is("YourValue"))));

2
これは(ないassertj)hamcrest溶液である-ちょうど側ノードとして
ハルトムートP.

46

特にハムクレストではありませんが、ここで言及する価値があると思います。私がJava8で頻繁に使用するのは次のようなものです。

assertTrue(myClass.getMyItems().stream().anyMatch(item -> "foo".equals(item.getName())));

(Rodrigo Manyariのわずかな改善を編集。少し冗長ではありません。コメントを参照してください。)

少し読みにくいかもしれませんが、タイプとリファクタリングの安全性が好きです。また、複数のBeanプロパティを組み合わせてテストすることもできます。たとえば、フィルターラムダにjavaのような&&式を使用します。


2
わずかな改善:assertTrue(myClass.getMyItems()。stream()。anyMatch(item-> "foo" .equals(item.getName()));
Rodrigo Manyari 2016年

@RodrigoManyariは、閉じ括弧がありません
Abdull

1
このソリューションは、適切なエラーメッセージを表示する可能性を無駄にします。
Giulio Caccin

@GiulioCaccin私はそうは思わない。JUnitを使用する場合は、オーバーロードされたアサーションメソッドを使用して、assertTrue(...、 "My own test failure message");を記述できます。junit.org/junit5/docs/current/api/org/junit/jupiter/api/…で
マリオ・

つまり、ブール値に対してアサーションを行うと、実際の/期待される差異を自動的に印刷する機能が失われます。マッチャーを使用してアサートすることは可能ですが、それを行うには、この応答をこのページの他のものと同様になるように変更する必要があります。
Giulio Caccin

20

Assertjはこれが得意です。

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

    assertThat(myClass.getMyItems()).extracting("name").contains("foo", "bar");

hamcrestと比較したassertjの大きなプラスは、コード補完を簡単に使用できることです。


16

AssertJはに優れた機能を提供します。sをextracting()渡してFunctionフィールドを抽出できます。コンパイル時にチェックを提供します。
最初に簡単にサイズをアサートすることもできます。

それは与えるでしょう:

import static org.assertj.core.api.Assertions;

Assertions.assertThat(myClass.getMyItems())
          .hasSize(2)
          .extracting(MyItem::getName)
          .containsExactlyInAnyOrder("foo", "bar"); 

containsExactlyInAnyOrder() リストには、順序に関係なくこれらの値のみが含まれていると断言します。

リストに順序に関係なくこれらの値が含まれているが、他の値も含まれている可能性があることを表明するには、次のコードを使用しますcontains()

.contains("foo", "bar"); 

補足として、aの要素から複数のフィールドをアサートするにはList、AssertJを使用して、各要素の期待値をtuple()関数にラップします。

import static org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple;

Assertions.assertThat(myClass.getMyItems())
          .hasSize(2)
          .extracting(MyItem::getName, MyItem::getOtherValue)
          .containsExactlyInAnyOrder(
               tuple("foo", "OtherValueFoo"),
               tuple("bar", "OtherValueBar")
           ); 

4
これに賛成票がない理由を理解しないでください。これが最善の答えだと思います。
PeMa 2018年

1
assertJライブラリは、JUnitアサーションAPIよりもはるかに読みやすくなっています。
Sangimed

@Sangimed Agreedと私はhamcrestよりもそれを好みます。
davidxxx 2018

私の意見では、これは「実際の値」を「期待値」から切り離し、それらを一致させる必要がある順序に配置するため、少し読みにくくなります。
テラン

5

リストが具象クラスである限り、MyItemsにequals()メソッドを実装している限り、単純にcontains()メソッドを呼び出すことができます。

// given 
// some input ... you to complete

// when
List<MyItems> results = service.getMyItems();

// then
assertTrue(results.contains(new MyItem("foo")));
assertTrue(results.contains(new MyItem("bar")));

アサートする値を受け入れるコンストラクターを実装したと想定します。これは1行ではないことに気づきましたが、両方を一度にチェックするのではなく、どの値が欠落しているかを知ることは有用です。


1
私はあなたの解決策が本当に好きですが、彼はテストのためにそのすべてのコードを変更する必要がありますか?
Kevin Bowersox 2012

ここでのすべての回答には、いくつかのテスト設定、テストするメソッドの実行、およびプロパティのアサートが必要であることを理解しています。私が見ることができるものから私の答えに実際のオーバーヘッドはありません。失敗したアサーションが欠落している値を明確に識別できるように、シープラートラインに2つのアサーションがあることだけです。
ブラッド

エラーメッセージがわかりやすいように、assertTrue内にメッセージを含めることも最適です。メッセージがない場合、失敗すると、JUnitはエラーメッセージなしでAssertionFailedErrorをスローします。したがって、「結果には新しいMyItem(\ "foo \")が含まれている必要があります」などを含めるのが最善です。
最大

はい、あなたは正しいです。私はどのような場合でもHamcrestをお勧めします。最近はassertTrue()を使用しません
ブラッド

余談

1

AssertJ 3.9.1は、anyMatchメソッドでの直接の述語の使用をサポートします。

assertThat(collection).anyMatch(element -> element.someProperty.satisfiesSomeCondition())

これは一般に、任意の複雑な条件に適した使用例です。

単純な条件の場合は、extractingメソッド(上記を参照)を使用することをお勧めします。結果として生じるテスト対象の反復可能オブジェクトが、読みやすさを向上させた値検証をサポートする可能性があるためです。例:containsFrank Neblungの回答のメソッドなどの特殊なAPIを提供できます。またはanyMatch、後でそれを呼び出して、などのメソッド参照を使用することもできます"searchedvalue"::equals。また、複数の抽出をextractingメソッドに入れることができ、結果は後でを使用して検証されtuple()ます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.