Ruby 如何比较RSpec中的两个哈希?

Ruby 如何比较RSpec中的两个哈希?,ruby,rspec,Ruby,Rspec,我有两个散列h1和h2,我想在RSpec中进行比较 我想检查h1的元素在经过一些转换后是否与h2相同,我们称之为f。也就是说,我想验证对于h1中的每个键k,h1[k]==f(h2[k]) 例如,如果h2中的所有值是h1中相应值的两倍,那么我想检查h1中的每个键k,h2[k]==h1[k]*2 在RSpec中,正确的方法是什么?目前我有: h1 = ... expect( h2.all? { |k,v| v == f(h1[k]) } ).to be true 但这看起来很笨重

我有两个散列
h1
h2
,我想在RSpec中进行比较

我想检查
h1
的元素在经过一些转换后是否与
h2
相同,我们称之为
f
。也就是说,我想验证对于
h1
中的每个键
k
h1[k]==f(h2[k])

例如,如果
h2
中的所有值是
h1
中相应值的两倍,那么我想检查h1中的每个键
k
h2[k]==h1[k]*2

在RSpec中,正确的方法是什么?目前我有:

h1 = ...
expect(
  h2.all? { |k,v|
    v == f(h1[k])
  }
).to be true
但这看起来很笨重

h1.each do |k, v|
  expect(v).to eq(f(h2[k]))
end
对我来说,它似乎更具可读性。

对于确切的等式:

expect(h1).to eq h2.map { |k, v| [k, f(v)] }.to_h

听起来您正在测试的是转换。我会考虑写这样的东西:

it "transforming something does something" do
  base_data = { k1: 1, k2: 2 }
  transformed_data = base_data.each_with_object({}) { |(k, v), t|
    t[k] = f(v)
  }

  expect(transformed_data).to eq(
    k1: 2,
    k2: 4,
  )
end
对我来说,描述清楚地说明了我们的期望。然后,我可以很容易地从测试中看出输入和预期输出是什么。此外,这还利用了哈希匹配器,它将在出现故障时提供两个哈希的良好差异:

expected: {:k1=>2, :k2=>4}
     got: {:k1=>1, :k2=>4}

(compared using ==)

Diff:
@@ -1,3 +1,3 @@
-:k1 => 2,
+:k1 => 1,
 :k2 => 4,
尽管我会质疑关键价值关系的含义。这些只是您试图运行的测试用例吗?如果是这样的话,我会让每一个测试都是独一无二的。如果还有其他问题,那么我可能会问,为什么转换方法没有提供散列作为开始。

如何:

h2 = f(h1)

expect(h2.keys).to eq(h1.keys)  # I assume you want this, too

h1.keys.each do |k|
  expect(h2[k]).to eq(h1[k] * 2) 
end

有点冗长,但可能更可读?

如果有人来寻找大嵌套散列的更好的差异,我想到了这个:

RSpec::Matchers.define :be_a_hash_like do |expected_hash|
  match do |actual_hash|
    matching_results = actual_hash == expected_hash
    unless matching_results
      system(
        "git diff $(echo '#{JSON.pretty_generate(expected_hash)}' | git hash-object -w --stdin) " +
                 "$(echo '#{JSON.pretty_generate(actual_hash)}' | git hash-object -w --stdin) --word-diff",
        out: $stdout,
        err: :out
      )
    end
    matching_results
  end

  failure_message { 'Look at the Diff above! ^^^' }
end

# then use:
expect(actual).to be_a_hash_like(expected)
原意:

输出示例:

我们在RSPEC中用来处理这个问题

我们开发了一个定制匹配器:

RSpec::Matchers.define :match_hash do |expected|
  match do |actual|
    Hashdiff.best_diff(expected, actual).blank?
  end
  failure_message do |actual|
    "expected that #{actual} would match #{expected}, but it has these differences: #{Hashdiff.best_diff(expected, actual)}"
  end
end

我们是这样使用的:
expect(实际的\u散列)。为了匹配\u散列(expected\u散列)

我会创建一个助手方法
equal?(其他)
来进行计算——从那里开始,
expect(h2.equal?(h1))。如果是真的
你的问题是非常容易误导的。您正在切换解释和代码中的
h1
h2
角色。此外,您的描述(以及代码)说明匹配是单向的,即解释文本中的
h2
是否有
h1
以外的键并不重要。这是你想要的吗?