Rspec: «array.should == another_array», но не заботясь о порядке

235

Я часто хочу сравнить массивы и убедиться, что они содержат одинаковые элементы в любом порядке. Есть ли краткий способ сделать это в RSpec?

Вот методы, которые не приемлемы:

#to_set

Например:

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

или

array.to_set.should == another_array.to_set

Это не удается, когда массивы содержат повторяющиеся элементы.

#sort

Например:

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

или

array.sort.should == another_array.sort

Это терпит неудачу, когда элементы массива не реализуют #<=>

nicholaides
источник
7
Не для умников, но для сравнения to_setи на sizeсамом деле не делает то, что вы хотите. Например, [a, b, b] будет соответствовать [a, a, b]. Ура!
Джо Лисс
3
Для тех, кто споткнулся здесь, интересует обратное: порядок должен быть таким же . Используйте eqсовпадения, напримерexpect([1, 2]).to_not eq([2, 1])
Деннис

Ответы:

263

Пытаться array.should =~ another_array

Лучшая документация по этому вопросу, которую я могу найти, это сам код, который находится здесь .

x1a4
источник
Это не учитывает порядок, так что это не приемлемый ответ, не так ли? Цитата из документации : Passes if actual contains all of the expected regardless of order..
Джошуа Мухайм
16
Заголовок этого поста: «Rspec:« array.should == another_array », но без заботы о порядке»
x1a4
3
Теперь это официально задокументировано под операторами сопоставления
Кельвин,
7
Если вы используете новый синтаксис «ожидайте», найденный в rspec 3.0, посмотрите ответ от @JoshKovach.
Clozach
46
Синтаксис Rspec 3.0 : expect([1, 2, 3]).to match_array([2, 1, 3])смотрите: stackoverflow.com/a/19436763/33226
Гэвин Миллер
238

С RSpec 2.11 вы также можете использовать match_array.

array.should match_array(another_array)

Что может быть более читабельным в некоторых случаях.

[1, 2, 3].should =~ [2, 3, 1]
# vs
[1, 2, 3].should match_array([2, 3, 1])
Валентин Немцев
источник
8
да, только что обновил до rails 4 и = ~ перестал работать там, где match_array работает отлично, спасибо!
opsb
2
Я не знаю, если это более читабельно. Теперь это выглядит так, как будто должно быть точное совпадение, но это не так. Предыдущее замешательство было достаточно расплывчатым, чтобы ничего не значить для массива, поэтому у меня не было предубеждения. Может быть, это только я.
Трейказ
1
Для «точного», вы всегда имеете eq(), поэтому я думаю, что match_array()это достаточно расплывчато для меня.
Авенд
Это не работает для меня в упорядоченных списках. Он думает, что списки, которые имеют одинаковые элементы в другом порядке, одинаковы. :-(
Джангофан
FWIW match_arrayявляется псевдонимом для contain_exactly( документация )
Руи Диас
136

Я обнаружил, =~что он непредсказуем, и он потерпел неудачу без видимой причины. Прошлое 2.14, вы, вероятно, должны использовать

expect([1, 2, 3]).to match_array([2, 3, 1])
Джош Ковач
источник
17
Также действует в прошлом 3,0: expect([1, 2, 3]).to contain_exactly(2, 3, 1). relishapp.com/rspec/rspec-expectations/v/3-0/docs/…
clozach
13

Используйте match_array, который принимает другой массив в качестве аргумента, или contain_exactly, который принимает каждый элемент в качестве отдельного аргумента, и иногда полезен для удобства чтения. ( документы )

Примеры:

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

или

expect([1, 2, 3]).to contain_exactly 3, 2, 1
nicholaides
источник
3

Для RSpec 3 используйте contain_exactly:

См. Https://relishapp.com/rspec/rspec-expectations/v/3-2/docs/built-in-matchers/contain-exactly-matcher для деталей, но вот выдержка:

Сочетание contains_exactly обеспечивает способ проверки массивов друг против друга таким образом, чтобы игнорировать различия в порядке между фактическим и ожидаемым массивом. Например:

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

Как уже отмечали другие, если вы хотите утверждать обратное, что массивы должны соответствовать как содержимому, так и порядку, используйте eq:

    expect([1, 2, 3]).to    eq([1, 2, 3]) # pass
    expect([1, 2, 3]).to    eq([2, 3, 1]) # fail
Тим Диггинс
источник
1

не очень хорошо документировано, но я все равно добавил ссылки:

Rspec3 документы

expect(actual).to eq(expected)


Rspec2 документы

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

Блэр Андерсон
источник
12
Оба ожидают (фактический) .to eq (ожидаемый) и ожидают (фактический) .to match_array (ожидаемый) работают в rspec3, но они делают разные вещи. #match_array игнорирует порядок, а #eq - нет.
Gucki
1
Это не отвечает на вопрос, так как ОП специально просят игнорировать заказ.
NobodysNightmare
Да! Это сработало для меня. Сравнение, которое не выполняется, если порядок элементов не совпадает. Спасибо! Я имею в виду .to eqметод, а не match_array.
Джангофан