Recently while working on Airtasker we got the following error from our (pretty extensive) Rspec test suite:
Failures:
1) UsersController#show with user actions gets user actions
Failure/Error: assigns(:actions).should == actions
expected: []
got: [] (using ==)
# ./spec/controllers/users_controller_spec.rb:51:in `block (4 levels) in <top (required)>'
Finished in 4.46 seconds
11 examples, 1 failure
The fix ended up being fairly simple, simply reverse the output which causes the test to pass. This led to one of my collegues commenting that:
One of the empty arrays was backwards.
Not sure if Serious
I'm fairly certain he was joking, but I wanted to know exactly what was happening. I was able to replicate the issue in the rails console just by manually executing the test (which is a fantastic way of understanding code)
irb(main):018:0> a
=> []
irb(main):019:0> b
=> []
irb(main):020:0> a == b
=> false
It turns out that the the a
and b
are ActiveRecord::Relation
From there it was pretty easy to figure out what was happening, the Relation
class implements the equality
method ==
which Rspec was using. Because both objects are Relations
it compares their sql rather than the result.
When reversing the Relation it executes the sql and compares them as an array.
Lessons Learned
There are a few cool lessons here:
- Ruby isn't magic, source code is pretty easy to read.
- Try using irb or a debugger to figure out more about your particular issue.
- In your custom objects implement the equality method, or even better include comparable and implement
<=>
which will give you all of the comparison methods for free!