Does an RSpec2 matcher for matching Hashes exist?

16,922

Solution 1

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.

Solution 2

Since 8 months the gem rspec-matchers has support for matching hashes:

expected.should be_hash_matching(subhash_or_equal)

see here for more details: https://github.com/rspec/rspec-expectations/pull/79

Solution 3

I believe the eql? method checks only that the two hashes have the same content So IIRC in Rspec2 you can do:

    expected = {:foo => 1, 'baz' => 2}
    expected.should be_eql({'baz' => 2, :foo => 1})

And the test should pass

Share:
16,922

Related videos on Youtube

user1678401
Author by

user1678401

Software engineer working on a model based testing tool. Experienced in Ruby, Java, Python, AWK and associated technologies. Dabbles in Clojure, Haskell, Racket and C.

Updated on July 08, 2020

Comments

  • user1678401
    user1678401 almost 4 years

    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?

  • user1678401
    user1678401 over 13 years
    Yesterday late I found the problem: I was not actually comparing two Hashes: one had turned into an OrderedHash somewhere along the way. You can't glance that from the RSpec output and I'm a bit embarrassed to say this wasn't the first time I fell into this trap either :/
  • zetetic
    zetetic over 13 years
    Interesting. So an OrderedHash and a Hash with the same key/value pairs are not considered equal -- that's good to know.
  • nruth
    nruth about 8 years
    this seems to have been removed in rspec 3, but .to eql(x) works
  • nruth
    nruth about 8 years
    or in rspec 3, expect(x).to eql(y)