Rspec: "array.should == another_array" but without concern for order
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
Related videos on Youtube
nicholaides
I'm a software engineer and cofounder of PromptWorks, the premier Ruby and web consultancy in Philadelphia.
Updated on July 19, 2020Comments
-
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 about 13 yearsNot to smartass, but comparing
to_set
andsize
actually doesn't do what you want. E.g. [a, b, b] would match [a, a, b]. Cheers! -
Dennis over 8 yearsFor 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 over 11 yearsThis 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 over 11 yearsTitle of this post: "Rspec: “array.should == another_array” but without concern for order"
-
Kelvin over 10 yearsThis is now officially documented under operator matchers
-
opsb over 10 yearsyup, just upgraded to rails 4 and =~ stopped working where match_array works fine, thanks!
-
Hakanai about 10 yearsI 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 about 10 yearsFor "exact", you always have
eq()
, so I guessmatch_array()
is vague enough for me. -
clozach about 10 yearsIf you're using the new "expect" syntax found in rspec 3.0, see the answer from @JoshKovach.
-
clozach about 10 yearsAlso valid past 3.0:
expect([1, 2, 3]).to contain_exactly(2, 3, 1)
. relishapp.com/rspec/rspec-expectations/v/3-0/docs/… -
Harish2k22 about 9 yearsRspec 3.0 syntax is
expect([1, 2, 3]).to match_array([2, 1, 3])
see: stackoverflow.com/a/19436763/33226 -
Donovan Thomson about 9 yearshow 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 over 8 yearsBoth 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 almost 8 yearsThis does not answer the question, since the OP specifically asked to disregard the order.
-
djangofan almost 8 yearsThis doesn't work for me on ordered lists. It thinks lists, which have the same items in a different order, are the same. :-(
-
djangofan almost 8 yearsYes! 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 thematch_array
. -
Ruy Diaz over 4 yearsAdding to what @GavinMiller mentioned (and as pointed out in the references SO link),
match_array
is an alias forcontain_exactly
, as seen in the documentation -
Ruy Diaz over 4 years