Rspec: “array.should == another_array” tetapi tanpa memperhatikan pesanan

235

Saya sering ingin membandingkan array dan memastikan bahwa mereka mengandung elemen yang sama, dalam urutan apa pun. Apakah ada cara ringkas untuk melakukan ini di RSpec?

Berikut adalah metode yang tidak dapat diterima:

#to_set

Sebagai contoh:

expect(array.to_set).to eq another_array.to_set

atau

array.to_set.should == another_array.to_set

Ini gagal ketika array berisi item duplikat.

#sort

Sebagai contoh:

expect(array.sort).to eq another_array.sort

atau

array.sort.should == another_array.sort

Ini gagal ketika elemen array tidak diimplementasikan #<=>

nicholaides
sumber
7
Bukan untuk sok pintar, tetapi membandingkan to_setdan sizesebenarnya tidak melakukan apa yang Anda inginkan. Misalnya [a, b, b] akan cocok dengan [a, a, b]. Bersulang!
Jo Liss
3
Bagi mereka yang tersandung di sini bertanya-tanya sebaliknya: urutannya harus sama . Gunakan eqpencocokan, misalnyaexpect([1, 2]).to_not eq([2, 1])
Dennis

Jawaban:

263

Mencoba array.should =~ another_array

Dokumentasi terbaik tentang ini dapat saya temukan adalah kode itu sendiri, yang ada di sini .

x1a4
sumber
Ini tidak memperhitungkan pesanan, jadi ini bukan jawaban yang dapat diterima, bukan? Mengutip dari docs : Passes if actual contains all of the expected regardless of order..
Joshua Muheim
16
Judul posting ini: "Rspec:" array.should == another_array "tetapi tanpa memperhatikan pesanan"
x1a4
3
Ini sekarang secara resmi didokumentasikan di bawah pencocokan operator
Kelvin
7
Jika Anda menggunakan sintaks "harapan" baru yang ditemukan di rspec 3.0, lihat jawabannya dari @JoshKovach.
clozach
46
Sintaks Rspec 3.0 dapat expect([1, 2, 3]).to match_array([2, 1, 3])dilihat: stackoverflow.com/a/19436763/33226
Gavin Miller
238

Karena RSpec 2.11 Anda juga dapat menggunakan match_array.

array.should match_array(another_array)

Yang bisa lebih mudah dibaca dalam beberapa kasus.

[1, 2, 3].should =~ [2, 3, 1]
# vs
[1, 2, 3].should match_array([2, 3, 1])
Valentin Nemcev
sumber
8
ya, baru saja ditingkatkan ke rails 4 dan = ~ berhenti bekerja di mana match_array berfungsi dengan baik, terima kasih!
opsb
2
Saya tidak tahu apakah itu lebih mudah dibaca. Sekarang bunyinya seperti itu harus sama persis, tapi tidak. Keributan sebelumnya cukup samar untuk tidak berarti apa-apa untuk sebuah array, jadi saya tidak memiliki prasangka. Mungkin hanya aku.
Trejkaz
1
Untuk "tepat", Anda selalu punya eq(), jadi saya kira match_array()cukup samar untuk saya.
awendt
Ini tidak berfungsi untuk saya pada daftar yang dipesan. Itu berpikir daftar, yang memiliki item yang sama dalam urutan berbeda, adalah sama. :-(
Djangofan
FWIW match_arrayadalah alias untuk contain_exactly( dokumentasi )
Ruy Diaz
136

Saya menemukan =~hal yang tidak dapat diprediksi dan gagal tanpa alasan yang jelas. Melewati 2,14, Anda mungkin harus menggunakan

expect([1, 2, 3]).to match_array([2, 3, 1])
Josh Kovach
sumber
17
Juga masa lalu yang valid 3.0: expect([1, 2, 3]).to contain_exactly(2, 3, 1). relishapp.com/rspec/rspec-expectations/v/3-0/docs/…
clozach
13

Gunakan match_array, yang menggunakan array lain sebagai argumen, atau contain_exactly, yang menggunakan setiap elemen sebagai argumen terpisah, dan terkadang berguna untuk keterbacaan. ( docs )

Contoh:

expect([1, 2, 3]).to match_array [3, 2, 1]

atau

expect([1, 2, 3]).to contain_exactly 3, 2, 1
nicholaides
sumber
3

Untuk RSpec 3 gunakan contain_exactly:

Lihat https://relishapp.com/rspec/rspec-expectations/v/3-2/docs/built-in-matchers/contain-exactly-matcher untuk detailnya, tapi inilah kutipannya:

Matcher content_exactly menyediakan cara untuk menguji array terhadap satu sama lain dengan cara yang mengabaikan perbedaan dalam pemesanan antara array aktual dan yang diharapkan. Sebagai contoh:

    expect([1, 2, 3]).to    contain_exactly(2, 3, 1) # pass
    expect([:a, :c, :b]).to contain_exactly(:a, :c ) # fail

Seperti yang telah ditunjukkan orang lain, jika Anda ingin menegaskan sebaliknya, bahwa array harus cocok dengan konten dan pesanan, kemudian gunakan eq, yaitu .:

    expect([1, 2, 3]).to    eq([1, 2, 3]) # pass
    expect([1, 2, 3]).to    eq([2, 3, 1]) # fail
Tim Diggins
sumber
1

tidak didokumentasikan dengan baik tetapi saya menambahkan tautan:

Dokumen Rspec3

expect(actual).to eq(expected)


Rspec2 docs

expect([1, 2, 3]).to match_array([2, 3, 1])

Blair Anderson
sumber
11
Keduanya mengharapkan (aktual). Hingga eq (diharapkan) dan mengharapkan (aktual). Untuk match_array (diharapkan) bekerja di rspec3, tetapi mereka melakukan hal yang berbeda. #match_array mengabaikan urutan, sedangkan #eq tidak.
gucki
1
Ini tidak menjawab pertanyaan, karena OP secara khusus diminta untuk mengabaikan pesanan.
NobodysNightmare
Iya! Ini berhasil untuk saya. Perbandingan yang gagal jika urutan elemen tidak sama. Terima kasih! Saya merujuk pada .to eqmetode, bukan match_array.
Djangofan