Rspec: проверьте, включает ли массив объект, который включает свойство
У меня есть массив json, полный объектов.
my_array = [{id => 6, name => "bob"},
{id => 5, name => "jim"},
{id => 2, name => "steve"}]
Мне нужно выяснить, содержит ли массив объект, который содержит атрибут "id", который установлен в 5. Атрибут "name" неизвестен.
Как это сделать в rspec?
Я знаю, если бы у меня был атрибут имени, который я знаю, я мог бы просто сделать:
my_array.should include({:id => 5, :name => "jim"})
Ответы
Ответ 1
expect(myArray.find { |item| item[:id] == 5 }).to_not be_nil
или с синтаксисом устаревшего синтаксиса
myArray.find { |item| item[:id] == 5 }.should_not be_nil
Обратите внимание, что myArray
не соответствует правилам Ruby. Переменные используют подчеркивание
my_array
не camelcase
myArray
Ответ 2
Это стоило бы того, если бы вы делали многие из них, но вы могли бы определить пользовательский макет:
RSpec::Matchers.define :object_with_id do |expected|
match do |actual|
actual[:id] == expected
end
description do
"an object with id '#{expected}'"
end
end
# ...
myArray.should include(object_with_id 5)
Ответ 3
Поместите этот макет any
в spec/support/matchers.rb
и потребуйте его в spec_helper.rb
RSpec::Matchers.define :any do |matcher|
match do |actual|
actual.any? do |item|
matcher.matches?(item)
end
end
end
Затем вы можете использовать его в следующих примерах:
expect(my_array).to any(include(id: 5))
Ответ 4
Здесь пользовательский соединитель "include_object" (возможно, лучшее имя должно использоваться, поскольку оно просто проверяет наличие идентификатора)
используется следующим образом
obj = {id:1}
objs = [{id: 1}, {id: 2}, {id: 3}]
expect(objs).to include_object obj
Матчи могут обрабатывать объекты, хеши (символы или строки)
Он также выводит только идентификатор в массиве на исключение для более удобного просмотра
RSpec::Matchers.define :include_object do |expected|
ids = []
match do |actual|
ids = actual.collect { |item| item['id'] || item[:id] || item.id }
ids.find { |id| id.to_s == expected.id.to_s }
end
failure_message_for_should_not do |actual|
"expected that array with object id #{ids} would contain the object with id '#{expected.id}'"
end
failure_message_for_should_not do |actual|
"expected that array with object id #{ids} would not contain the object with id '#{expected.id}'"
end
end
Ответ 5
Вы можете развернуть массив и проверить соответствие двух массивов, как здесь:
expect(my_array).to include(*compare_array)
Он разворачивается и сопоставляет каждое значение массива.
Это эквивалентно этому:
expected([1, 3, 7]).to include(1,3,7)
Источник: Дополнительная документация
Ответ 6
Я бы использовал RSpec 3 с составным include
следующим образом:
expect(my_array).to include(include(id: 5))
Это может привести к более подробному выводу через RSpec в случае сбоя.
it 'expects to have element with id 3' do
my_array = [
{ id: 6, name: "bob" },
{ id: 5, name: "jim" },
{ id: 2, name: "steve" }
]
expect(my_array).to include(include(id: 3))
end
Это приведет к появлению следующего сообщения об ошибке:
Failures:
1) Test expects to have element with id
Failure/Error: expect(my_array).to include(include(id: 3))
expected [{:id => 6, :name => "bob"}, {:id => 5, :name => "jim"}, {:id => 2, :name => "steve"}] to include (include {:id => 3})
Diff:
@@ -1,2 +1,2 @@
-[(include {:id => 3})]
+[{:id=>6, :name=>"bob"}, {:id=>5, :name=>"jim"}, {:id=>2, :name=>"steve"}]
Дальнейшее чтение:
https://relishapp.com/rspec/rspec-expectations/docs/composing-matchers
Ответ 7
Это также возможно, используя псевдоним have_attributes:
expect(my_array).to include( an_object_having_attributes(id: 5) )
или, как в моем собственном случае использования, сопоставляя весь массив:
expect(my_array).to contain_exactly(
an_object_having_attributes(id: 5),
an_object_having_attributes(id: 6),
an_object_having_attributes(id: 2)
)