Rspec: "array.should == another_array" but without concern for order

76,765

Solution 1

Use match_array, which takes another array as an argument, or contain_exactly, which takes each element as a separate argument, and is sometimes useful for readability. (docs)

Examples:

expect([1, 2, 3]).to match_array [3, 2, 1]

or

expect([1, 2, 3]).to contain_exactly 3, 2, 1

Solution 2

Try array.should =~ another_array

The best documentation on this I can find is the code itself, which is here.

Solution 3

Since RSpec 2.11 you can also use match_array.

array.should match_array(another_array)

Which could be more readable in some cases.

[1, 2, 3].should =~ [2, 3, 1]
# vs
[1, 2, 3].should match_array([2, 3, 1])

Solution 4

I've found =~ to be unpredictable and it has failed for no apparent reason. Past 2.14, you should probably use

expect([1, 2, 3]).to match_array([2, 3, 1])

Solution 5

For RSpec 3 use contain_exactly:

See https://relishapp.com/rspec/rspec-expectations/v/3-2/docs/built-in-matchers/contain-exactly-matcher for details, but here's an extract:

The contain_exactly matcher provides a way to test arrays against each other in a way that disregards differences in the ordering between the actual and expected array. For example:

    expect([1, 2, 3]).to    contain_exactly(2, 3, 1) # pass
    expect([:a, :c, :b]).to contain_exactly(:a, :c ) # fail

As others have pointed out, if you want to assert the opposite, that the arrays should match both contents and order, then use eq, ie.:

    expect([1, 2, 3]).to    eq([1, 2, 3]) # pass
    expect([1, 2, 3]).to    eq([2, 3, 1]) # fail
Share:
76,765

Related videos on Youtube

nicholaides
Author by

nicholaides

I'm a software engineer and cofounder of PromptWorks, the premier Ruby and web consultancy in Philadelphia.

Updated on July 19, 2020

Comments

  • nicholaides
    nicholaides almost 4 years

    I often want to compare arrays and make sure that they contain the same elements, in any order. Is there a concise way to do this in RSpec?

    Here are methods that aren't acceptable:

    #to_set

    For example:

    expect(array.to_set).to eq another_array.to_set
    

    or

    array.to_set.should == another_array.to_set
    

    This fails when the arrays contain duplicate items.

    #sort

    For example:

    expect(array.sort).to eq another_array.sort
    

    or

    array.sort.should == another_array.sort
    

    This fails when the arrays elements don't implement #<=>

    • Jo Liss
      Jo Liss about 13 years
      Not to smartass, but comparing to_set and size actually doesn't do what you want. E.g. [a, b, b] would match [a, a, b]. Cheers!
    • Dennis
      Dennis over 8 years
      For those who stumbled here wondering the opposite: order should be the same. Use the eq matcher, e.g. expect([1, 2]).to_not eq([2, 1])
  • Joshua Muheim
    Joshua Muheim over 11 years
    This doesn't take the order in account, so this is not an acceptable answer, is it? Quote from the docs: Passes if actual contains all of the expected regardless of order..
  • x1a4
    x1a4 over 11 years
    Title of this post: "Rspec: “array.should == another_array” but without concern for order"
  • Kelvin
    Kelvin over 10 years
    This is now officially documented under operator matchers
  • opsb
    opsb over 10 years
    yup, just upgraded to rails 4 and =~ stopped working where match_array works fine, thanks!
  • Hakanai
    Hakanai about 10 years
    I dunno if that is more readable. Now it reads like it should be an exact match, but it isn't. The previous squiggle was vague enough to mean nothing for an array, so I didn't have the preconception. Maybe it's just me.
  • awendt
    awendt about 10 years
    For "exact", you always have eq(), so I guess match_array() is vague enough for me.
  • clozach
    clozach about 10 years
    If you're using the new "expect" syntax found in rspec 3.0, see the answer from @JoshKovach.
  • clozach
    clozach about 10 years
    Also valid past 3.0: expect([1, 2, 3]).to contain_exactly(2, 3, 1). relishapp.com/rspec/rspec-expectations/v/3-0/docs/…
  • Harish2k22
    Harish2k22 about 9 years
    Rspec 3.0 syntax is expect([1, 2, 3]).to match_array([2, 1, 3]) see: stackoverflow.com/a/19436763/33226
  • Donovan Thomson
    Donovan Thomson about 9 years
    how do you access the error message in the case of a mismatch ? I am trying to use this to describe the mismatch between two arrays within two higher level objects
  • gucki
    gucki over 8 years
    Both expect(actual).to eq(expected) and expect(actual).to match_array(expected) work in rspec3, but they are doing different things. #match_array ignores the ordering, while #eq does not.
  • NobodysNightmare
    NobodysNightmare almost 8 years
    This does not answer the question, since the OP specifically asked to disregard the order.
  • djangofan
    djangofan almost 8 years
    This doesn't work for me on ordered lists. It thinks lists, which have the same items in a different order, are the same. :-(
  • djangofan
    djangofan almost 8 years
    Yes! This worked for me. A comparison that fails if the order of elements is not the same. Thank you! I refer to the .to eq method, not the match_array .
  • Ruy Diaz
    Ruy Diaz over 4 years
    Adding to what @GavinMiller mentioned (and as pointed out in the references SO link), match_array is an alias for contain_exactly, as seen in the documentation
  • Ruy Diaz
    Ruy Diaz over 4 years
    FWIW match_array is an alias for contain_exactly (documentation)