Does an RSpec2 matcher for matching Hashes exist?

Confusion picture Confusion · Jan 18, 2011 · Viewed 16.6k times · Source

Note to future readers: think RSpec does not consider your Hashes equal? One might be an OrderedHash, but from the regular RSpec output you can't tell. This was the problem that prompted this post.

Original question:

Suppose I have a spec where I want to test that a method generates the appropriate Hash.

it 'should generate the Hash correctly' do
  expected = {:foo => 1, 'baz' => 2}
  subject.some_method_that_should_generate_the_hash.should == expected
end

This often fails, because different Hashes with the same key-value pairs may return their pairs in a different ordered. Results look like:

Failure/Error: subject.some_method_that_should_generate_the_hash.should == expected
expected: {:foo => 1, 'baz' => 2},
     got: {'baz' => 2, :foo => 1}

For arrays, this is solved using the =~ operator. However, that does not work for Hashes. For now, I've resorted to

it 'should generate the Hash correctly' do
  expected = {:foo => 1, 'baz' => 2}
  subject.some_method_that_should_generate_the_hash.each {|k,v|
    v.should == expected[k]
  }
end

but that seems unnecessarily verbose. I expect there to be an obvious solution for this. Am I overlooking something in the docs or doesn't RSpec have a proper Matcher for orderless Hash equality?

Answer

zetetic picture zetetic · Jan 19, 2011
describe 'Hash' do
  let(:x) { { :a => 1, :b => 2 } }
  let(:y) { { :b => 2, :a => 1 } }

  it "should be equal with ==" do
    x.should == y
  end
end

Passes. I'm not sure what's going on in your specific case. Do you have some failing examples you can share?

Programming Ruby has this to say:

Equality — Two hashes are equal if they have the same default value, they contain the same number of keys, and the value corresponding to each key in the first hash is equal (using ==) to the value for the same key in the second.