Hamcrest membandingkan koleksi


114

Saya mencoba membandingkan 2 daftar:

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

Tapi ide

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)

Bagaimana saya harus menulisnya?

Jawaban:


161

Jika Anda ingin menegaskan bahwa kedua daftar itu identik, jangan memperumit masalah dengan Hamcrest:

assertEquals(expectedList, actual.getList());

Jika Anda benar-benar ingin melakukan perbandingan tidak peka pesanan, Anda dapat memanggil containsInAnyOrdermetode varargs dan memberikan nilai secara langsung:

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

(Dengan asumsi bahwa daftar Anda adalah String , bukan Agent, untuk contoh ini.)

Jika Anda benar-benar ingin memanggil metode yang sama dengan konten dari List:

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

Tanpa ini, Anda memanggil metode dengan satu argumen dan membuat Matcheryang diharapkan cocok dengan di Iterablemana setiap elemen adalah List. Ini tidak dapat digunakan untuk mencocokkanList .

Artinya, Anda tidak dapat mencocokkan a List<Agent>dengan a Matcher<Iterable<List<Agent>>, yang coba dicoba oleh kode Anda.


+1 untuk "Jika Anda benar-benar ingin memanggil metode yang sama dengan isi Daftar". Sayangnya saya tidak bisa menyelesaikannya sendiri. Khususnya bahwa ada konstruktor yang mengambil koleksi.
Eyad Ebrahim

3
@Tim Tidak cukup; containsInAnyOrdermensyaratkan bahwa semua elemen ada, sehingga pernyataan pertama akan gagal. Lihat hasItemsapakah Anda ingin memeriksa bahwa setidaknya elemen tersebut ada.
Joe

4
Jika Anda menggunakan containsInAnyOrder, Anda harus terlebih dahulu memastikan kedua daftar memiliki ukuran yang sama ... Jika actual.getList()kebetulan berisi "item1", "item3", "item2", tes akan lulus dan mungkin Anda ingin memastikan hanya berisi item yang terdaftar ... Dalam hal ini Anda dapat menggunakan assertThat(actual.getList().size(), equalTo(2));sebelum containsInAnyOrder, dengan cara ini Anda memastikan kedua daftar memiliki konten yang sama.
Martin

1
@Anda sedang memikirkan hasItems. Pemeriksaan ekstra tidak diperlukan di sini. Lihat komentar untuk Tim di atas, dan juga Bagaimana perbedaan Hamcrest's hasItems, contains and containsInAnyOrder?
Joe

1
Pengguna Kotlin : jangan lupa untuk menambahkan operator spread ( *expectedList.toTypedArray()) saat meneruskan array sebagai vararg!
James Bowman

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

Versi lebih pendek dari jawaban @ Joe tanpa parameter yang berlebihan.


28

Untuk melengkapi jawaban @ Joe:

Hamcrest memberi Anda tiga metode utama untuk mencocokkan daftar:

contains Memeriksa kecocokan semua elemen dengan menghitung urutannya, jika daftar memiliki lebih banyak atau lebih sedikit elemen, itu akan gagal

containsInAnyOrder Memeriksa kecocokan semua elemen dan tidak masalah urutannya, jika daftar memiliki lebih banyak atau lebih sedikit elemen, akan gagal

hasItems Memeriksa hanya untuk objek yang ditentukan tidak masalah jika daftar memiliki lebih banyak

hasItem Memeriksa hanya satu objek, tidak masalah jika daftarnya memiliki lebih banyak

Semuanya dapat menerima daftar objek dan menggunakan equalsmetode untuk perbandingan atau dapat dicampur dengan pencocokan lain seperti @borjab disebutkan:

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 ...)


Agak terlambat ke pesta, tetapi terima kasih atas deskripsi perbedaan antara masing-masing metode.
Marcos de Andrade

Keputusan bagus dalam item daftar kasus bukanlah tipe primitif.
Stanislav Tsepa

Apakah ada cara yang aman untuk melakukan ini?
danresp

15

Dengan pustaka Hamcrest yang ada (mulai v.2.0.0.0) Anda dipaksa untuk menggunakan metode Collection.toArray () pada Koleksi Anda untuk menggunakan containsInAnyOrder Matcher. Jauh lebih baik menambahkan ini sebagai metode terpisah ke 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());
}

Sebenarnya saya akhirnya menambahkan metode ini ke pustaka pengujian khusus saya dan menggunakannya untuk meningkatkan keterbacaan kasus pengujian saya (karena lebih sedikit verbositas).


2
Bagus, saya akan menggunakan pembantu ini. Pesan assert di sini lebih informatif: memberi nama item yang hilang satu per satu, bukan hanya: daftarnya harus elem1, elem2, .. elem99, tapi saya mendapat elem1, elem2, ..., elem98 - semoga berhasil menemukan yang hilang.
pihentagy

3

Pastikan bahwa Objects dalam daftar Anda telah equals()ditentukan pada mereka. Kemudian

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

bekerja.


1

Untuk daftar objek Anda mungkin memerlukan sesuatu seperti ini:

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")))));
}

Gunakan containsInAnyOrder jika Anda tidak ingin memeriksa urutan objek.

PS Bantuan apa pun untuk menghindari peringatan yang ditekan akan sangat dihargai.


-3

Untuk membandingkan dua daftar dengan urutan yang diawetkan menggunakan,

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

Ini tidak menjawab pertanyaan itu.
kamczak

Itu sebagian.
rvazquezglez

@rvazquezglez Apa maksud Anda? Mengapa kamu mengatakan itu? Hasil dari metode ini tepat di lingkungan saya.
niaomingjian

@niaomingjian Kode ini memeriksa bahwa actualListmengandung elemen di dalam containsmatcher, yang akan gagal jika elemen tidak dalam urutan yang sama dan akan gagal juga jika mengandung lebih banyak elemen atau hilang satu.
rvazquezglez

@rvazquezglez jadi tujuan kode ini adalah untuk memeriksa persamaan yang tepat (panjang, nilai, dan urutan yang sama) dalam dua daftar, bukan?
niaomingjian
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.