このシグネチャを使用してメソッドを単体テストしたいとします:
List<MyItem> getMyItems();
MyItem
は多くのプロパティを持つPojoであり、そのうちの1つは"name"
であり、getName()
を介してアクセスすると仮定します。
検証に関心があるのは、List<MyItem>
、またはIterable
に2つのMyItem
インスタンスが含まれ、その"name"
プロパティの値が"foo"
および"bar"
。他のプロパティが一致しない場合、このテストの目的はあまり気にしません。名前が一致すれば、テストは成功です。
可能であればワンライナーにしたいと思います。ここに、私がやりたいと思う種類の「疑似構文」があります。
assert(listEntriesMatchInAnyOrder(myClass.getMyItems(), property("name"), new String[]{"foo", "bar"});
ハムクレストは、この種のことには適していますか?もしそうなら、上記の私の疑似構文の正確なバージョンは何でしょうか?
私を正しい方向に向けてくれた@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"))
));
試してください:
assertThat(myClass.getMyItems(),
hasItem(hasProperty("YourProperty", is("YourValue"))));
特にハムクレストではありませんが、ここで言及する価値があると思います。 Java8でよく使用するのは次のようなものです。
assertTrue(myClass.getMyItems().stream().anyMatch(item -> "foo".equals(item.getName())));
(ロドリゴ・マニャリのわずかな改善に編集。少し冗長です。コメントを参照してください。)
読むのが少し難しいかもしれませんが、タイプとリファクタリングの安全性が好きです。複数のBeanプロパティを組み合わせてテストするのにも便利です。例えばフィルタlambdaにJavaのような&&式を使用します。
Assertj はこれが得意です。
import static org.assertj.core.api.Assertions.assertThat;
assertThat(myClass.getMyItems()).extracting("name").contains("foo", "bar");
Hamcrestと比較したassertjの大きな利点は、コード補完を簡単に使用できることです。
AssertJはextracting()
で優れた機能を提供します:Function
sを渡してフィールドを抽出できます。コンパイル時にチェックを提供します。
最初に簡単にサイズをアサートすることもできます。
それは与えるだろう:
import static org.assertj.core.api.Assertions;
Assertions.assertThat(myClass.getMyItems())
.hasSize(2)
.extracting(MyItem::getName)
.containsExactlyInAnyOrder("foo", "bar");
containsExactlyInAnyOrder()
は、順序に関係なく、リストにはこれらの値のみが含まれていることを表明します。
順序に関係なくリストにこれらの値が含まれているが、他の値が含まれている可能性があることをアサートするには、contains()
を使用します。
.contains("foo", "bar");
サイドノートとして: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")
);
Listが具象クラスである限り、MyItemに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")));
アサートする値を受け入れるコンストラクターを実装したと仮定します。これは一行ではありませんが、両方を一度にチェックするよりも、どの値が欠落しているかを知ることは有用です。