Hamcrestのコレクションを比較する


114

2つのリストを比較しようとしています。

assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));

しかし、アイデア

java: no suitable method found for assertThat(java.util.List<Agent>,org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>>)
method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<T>) is not applicable
  (no instance(s) of type variable(s) T exist so that argument type org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>> conforms to formal parameter type org.hamcrest.Matcher<T>)
method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<T>) is not applicable
  (cannot instantiate from arguments because actual and formal argument lists differ in length)

どのように書けばよいですか?

回答:


161

2つのリストが同一であると主張したい場合は、Hamcrestで複雑にしないでください。

assertEquals(expectedList, actual.getList());

順序に依存しない比較を実際に実行する場合は、containsInAnyOrdervarargsメソッドを呼び出して値を直接指定できます。

assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));

(この例StringではAgent、リストがではなくであると想定しています。)

あなたが本当に同じ内容をaの内容で呼び出したい場合List

assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));

これがなければ、あなたは、単一の引数を持つメソッドを呼び出して、作成しているMatcherと一致するように期待しているIterableところ各要素はあるがList。これはとの一致には使用できませんList

つまり、あなたが一致しないことができList<Agent>Matcher<Iterable<List<Agent>>、あなたのコードをしようとしているものです。


「本当に同じメソッドをリストの内容で呼び出したい場合」の+1。悲しいことに、私はそれを自分で解決することができませんでした。特に、コレクションを受け取るコンストラクターがあることです。
Eyad Ebrahim 2014

3
@Timよくありません。最初のアサーションが失敗するように、すべての要素が存在containsInAnyOrderする必要があります。参照してください。hasItemsあなたがいることを確認したい場合は、少なくともこれらの要素が存在しています。
Joe

4
containsInAnyOrderを使用する場合は、最初に両方のリストが同じサイズであることを確認する必要があります... actual.getList()が含まれている"item1", "item3", "item2"場合、テストに合格し、リストされている項目のみが含まれていることを確認したい場合があります...その場合は、assertThat(actual.getList().size(), equalTo(2));containsInAnyOrderの前に、この方法で両方のリストの内容が同じであることを確認します。
マーティン

1
あなたが考えている@マーティンhasItems。ここでは余分なチェックは不要です。上記のTimへのコメントと、HamcrestのhasItems、contains、containsInAnyOrderの違いを参照してください。
Joe

1
Kotlinユーザー*expectedList.toTypedArray()配列を可変引数として渡す場合は、スプレッド演算子()を追加することを忘れないでください。
James Bowman

62
List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));

冗長なパラメータなしの@Joeの回答の短いバージョン。


28

@Joeの回答を補足するには:

Hamcrestは、リストを照合する3つの主要な方法を提供します。

contains 順序を考慮に入れてすべての要素の一致をチェックします。リストに含まれる要素の数が多かったり少なかったりすると、失敗します

containsInAnyOrder すべての要素の一致をチェックし、順序は問題ではありません。リストに含まれる要素の数が多かったり少なかったりすると、失敗します

hasItems 指定されたオブジェクトのみをチェックし、リストにそれ以上あるかどうかは関係ありません

hasItem 1つのオブジェクトのみをチェックし、リストにそれ以上あるかどうかは関係ありません

それらのすべてはオブジェクトのリストを受け取り、equals比較のためにメソッドを使用するか、または言及された@borjabのような他のマッチャーと混合することができます:

assertThat(myList , contains(allOf(hasProperty("id", is(7L)), 
                                   hasProperty("name", is("testName1")),
                                   hasProperty("description", is("testDesc1"))),
                             allOf(hasProperty("id", is(11L)), 
                                   hasProperty("name", is("testName2")),
                                   hasProperty("description", is("testDesc2")))));

http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#contains(E ...) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html #containsInAnyOrder(java.util.Collection) http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#hasItems(T ...)


パーティーには少し遅れましたが、各方法の違いの説明に感謝します。
Marcos de Andrade

リストアイテムがプリミティブタイプではない場合の大きな決定。
Stanislav Tsepa

これを行うタイプセーフな方法はありますか?
andresp

15

既存のHamcrestライブラリ(v.2.0.0.0以降)では、containsInAnyOrderマッチャーを使用するために、コレクションでCollection.toArray()メソッドを使用する必要があります。これを別のメソッドとしてorg.hamcrest.Matchersに追加するほうがはるかに便利です。

public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(Collection<T> items) {
    return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder((T[]) items.toArray());
}

実際、私はこのメソッドをカスタムテストライブラリに追加し、それを使用してテストケースの読みやすさを向上させました(冗長性が低いため)。


2
いいですね、このヘルパーを使います。ここでのアサートメッセージはより有益です:不足している項目に1つずつ名前を付けるだけでなく、次のように名前を付けます。行方不明のものを見つける。
pihentagy

3

Objectリストのがequals()定義されていることを確認してください。その後

    assertThat(generatedList,is(equalTo(expectedList)));

動作します。


1

オブジェクトのリストについては、次のようなものが必要になる場合があります。

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

@Test
@SuppressWarnings("unchecked")
public void test_returnsList(){

    arrange();
  
    List<MyBean> myList = act();
    
    assertThat(myList , contains(allOf(hasProperty("id",          is(7L)), 
                                       hasProperty("name",        is("testName1")),
                                       hasProperty("description", is("testDesc1"))),
                                 allOf(hasProperty("id",          is(11L)), 
                                       hasProperty("name",        is("testName2")),
                                       hasProperty("description", is("testDesc2")))));
}

オブジェクトの順序を確認しない場合containsInAnyOrderを使用します。

PS推奨されていない警告を回避するための助けがあれば、本当にありがたいです。


-3

2つのリストを保存された順序で比較するには、

assertThat(actualList, contains("item1","item2"));

これは質問の答えにはなりません。
kamczak

それは部分的にします。
rvazquezglez 2016年

@rvazquezglezどういう意味ですか?どうしてそんなこと言うの?メソッドの結果は私の環境にぴったりです。
niaomingjian

@niaomingjianコードは、actualListcontainsmatcher 内に要素を含んでいることをチェックしています。要素が同じ順序でない場合は失敗し、要素がさらに含まれている場合や欠落している場合も失敗します。
rvazquezglez

@rvazquezglezなので、コードの目的は、2つのリストの正確な等価性(同じ長さ、値、順序)を調べることですよね?
niaomingjian
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.