RSpec:检查数组是否包含包含属性的对象

yrwegjxp  于 2022-10-15  发布在  Ruby
关注(0)|答案(8)|浏览(231)

我有一个充满对象的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"})
mzillmmw

mzillmmw1#

expect(myArray.find { |item| item[:id] == 5 }).to_not be_nil

或者使用传统的HASS语法

myArray.find { |item| item[:id] == 5 }.should_not be_nil

请注意,myArray不遵循Ruby约定。变量使用下划线

my_array

不是卡梅尔凯斯

myArray
mv1qrgav

mv1qrgav2#

也可以使用HAVING_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)
)
7lrncoxx

7lrncoxx3#

您可以展开一个数组并检查两个数组的匹配情况,如下所示:

expect(my_array).to include(*compare_array)

它将展开并匹配数组的每个值。
它相当于:

expected([1, 3, 7]).to include(1,3,7)

来源:味觉文档

oewdyzsn

oewdyzsn4#

只有当您执行其中的许多操作时,这才是值得的,但您可以定义一个自定义匹配器:

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

zz2j4svz5#

将这个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))
bjp0bcyl

bjp0bcyl6#

我会这样使用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

hivapdat

hivapdat7#

下面是一个客户匹配器“INCLUDE_OBJECT”(可能应该使用一个更好的名称,因为它只是检查id是否存在)
用法如下

obj = {id:1}
objs = [{id: 1}, {id: 2}, {id: 3}]
expect(objs).to include_object obj

Matcher可以处理Object、Hashs(符号或字符串),它还只打印数组中的id,以便于查看

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's #{ids} would contain the object with id '#{expected.id}'"
  end

  failure_message_for_should_not do |actual|
    "expected that array with object id's #{ids} would not contain the object with id '#{expected.id}'"
  end
end
ws51t4hk

ws51t4hk8#

我看到有许多响应,但在需要检查每个数组对象上的多个键-值对而不是单个属性检查的情况下,这里有一个实现对我很有帮助

使用情况

expect(array).to include(have_attributes_with_values({ id: 5, name: 'Jim' }))

Matcher实现

RSpec::Matchers.define :have_attributes_with_values do |expected|
  match do |actual|
    expected.each do |key, value|
      return false unless actual[key] == value
    end
  end
end

相关问题