Rspec匹配哈希数组

36

我有一个哈希数组,为了举例子,它看起来像这样:

[{"foo"=>"1", "bar"=>"1"}, {"foo"=>"2", "bar"=>"2"}]

使用Rspec,我想测试数组中是否存在"foo" => "2",但我不关心它是第一个还是第二个条目。 我已经尝试过:

[{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}].should include("foo" => "2"))

但是这样不起作用,因为哈希应该完全匹配。是否有任何方法可以部分测试每个哈希的内容?


1
[{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}].flat_map(&:to_a).should include(["foo","2"]) 这段代码也可以正常工作。 - Arup Rakshit
5个回答

49

怎么样?

hashes = [{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}]
expect(hashes).to include(include('foo' => '2'))

1
如果你想要全部而不是任意一个,那么你可以使用 all: expect(hashes).to all(include('foo' => '2')) - Alexey Shein
这里是all的文档:https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/all-matcher - Kris
19
这个可以用,不过我会这么说:expect(hashes).to include(a_hash_including("foo" => "2")) - Elliot Winkler

19

使用可组合的匹配器

hashes = [{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}]
expect(hashes)
  .to match([
    a_hash_including('foo' => '2'), 
    a_hash_including('foo' => '1')
  ])

12
你可以使用any?方法。请查看此文档
hashes = [{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}]
expect(hashes.any? { |hash| hash['foo'] == '2' }).to be_true

非常感谢,你救了我的一天。 - Laurent
感谢您提供的简洁解决方案。FWIW,我使用了.to be_truthy - i0x539

7
你可以使用可组合的匹配器。

http://rspec.info/blog/2014/01/new-in-rspec-3-composable-matchers/

但我更喜欢像这样定义自定义匹配器。
require 'rspec/expectations'

RSpec::Matchers.define :include_hash_matching do |expected|
  match do |array_of_hashes|
    array_of_hashes.any? { |element| element.slice(*expected.keys) == expected }
  end
end

并在规范中像这样使用它
describe RSpec::Matchers do
  describe '#include_hash_matching' do
    subject(:array_of_hashes) do
      [
        {
          'foo' => '1',
          'bar' => '2'
        }, {
          'foo' => '2',
          'bar' => '2'
        }
      ]
    end

    it { is_expected.to include_hash_matching('foo' => '1') }

    it { is_expected.to include_hash_matching('foo' => '2') }

    it { is_expected.to include_hash_matching('bar' => '2') }

    it { is_expected.not_to include_hash_matching('bar' => '1') }

    it { is_expected.to include_hash_matching('foo' => '1', 'bar' => '2') }

    it { is_expected.not_to include_hash_matching('foo' => '1', 'bar' => '1') }

    it 'ignores the order of the keys' do
      is_expected.to include_hash_matching('bar' => '2', 'foo' => '1')
    end
  end
end


Finished in 0.05894 seconds
7 examples, 0 failures

如果你想让它与使用符号的哈希配合工作,可以这样做:RSpec::Matchers.define :include_hash_matching do |expected| match do |array_of_hashes| array_of_hashes.any? do |element| expected = expected.stringify_keys element = element.stringify_keys element.slice(*expected.keys) == expected end end end - Connor Shea

0
如果分别测试哈希值不是严格要求,我会这样做:
[{"foo" => "1", "bar" => "2"}, {"foo" => "2", "bar" => "2"}].map{ |d| d["foo"] }.should include("2")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接