DEV Community

Andy Huynh
Andy Huynh

Posted on

the difference between RSpec eq and be

ruby

RSpec has two equality matchers: eq and be. Depending on the circumstances, eq works most of the time. The difference between the two is subtle. The result of understanding the difference will yield clearer and more reliable specs.

Take this contrived example which expects a user name to be "Jon".

RSpec.describe User, "#name", type: :model do
  let(:user) { Fabricate(:user, name: "Jon") }

  scenario "User's name is Jon" do
    expect(user.name).to be("Jon")
  end
end
Enter fullscreen mode Exit fullscreen mode

Running this test we get a failure.

Failures:

  1) User's name is Jon
     Failure/Error: expect(user.name).to be "Jon"

       expected #<String:70298288643660> => "Jon"
            got #<String:70298288643700> => "Jon"
...
...
Enter fullscreen mode Exit fullscreen mode

It's failing and rightfully so! RSpec's be matcher expects both entities to be the same object. In other words, user.name and the string "Jon" are expected to have the same object_id.

irb
irb(main):001:0> jon = "Jon"
=> "Jon" 
irb(main):002:0> "Jon"
=> "Jon" 
irb(main):003:0> jon == "Jon"
=> true
irb(main):004:0> jon.equal?("Jon")
=> false
irb(main):005:0> jon.object_id
=> 70185646150880
irb(main):005:0> "Jon".object_id
=> 70185646097920
Enter fullscreen mode Exit fullscreen mode

Notice the object ids are different. Under the hood, RSpec is calling Object#equal? which is a check at the object level.

RSpec's eq, is what you expect the string value to be matched against. Going back to our earlier example:

RSpec.describe User, "#name", type: :model do
  let(:user) { Fabricate(:user, name: "Jon") }

  scenario "User's name is Jon" do
    expect(user.name).to eq("Jon")
  end
end
Enter fullscreen mode Exit fullscreen mode

After you run your spec, you're passing!

Finished in 1.12 seconds (files took 13.85 seconds to load)
1 example, 0 failures

Randomized with seed 4227
...
...
Enter fullscreen mode Exit fullscreen mode

The user's name value is "jon". That's the same as the value of the string "Jon". Peaking under the hood again.. RSpec eq invokes === on the two objects which checks the return value.

TLDR

eq checks if the object values are the same

be checks if the objects are the same

Read more, here.

Oldest comments (1)

Collapse
 
cescquintero profile image
Francisco Quintero πŸ‡¨πŸ‡΄

Great to know this.. I always try to use be() for object checks. eq() for values and eql() values of the same type.