differences of "be", "eq", "eql" and "equal" in RSpec

rubyonrails rspec

In RSpec, when you first start writing test cases to compare expected results, it might be very confusing to pick from "be", "eq", "eql" or "equal".

However, once you know the underlying differences of these methods, everything will be clear afterward. Let me go through them here with some examples.

Compare Statements

There are 2 groups of compare methods.

The followings compare the value of the object:

These two compare the object_id of the object instead:

Test Case Example

In the following test case, I am going to use String, Array and Fixnum data to demonstrate the differences of "eq", "eql", "equal", "be".

Fixnum

require 'rails_helper'

describe 'Fixnum' do  
  it('should find two Fixnums are equal') { 1.should eq 1 }
  it('should find two Fixnums are equal') { 1.should eql 1 }
  it('should find two Fixnums are equal') { 1.should equal 1 }
  it('should find two Fixnums are equal') { 1.should be 1 }
end  

In case of Fixnum, it will all process successful. It is because Fixnum with the same value are actually the same single data instance, i.e. 1 and 1 are referring the same instance in the memory.

String

describe 'String' do  
  it('should find two strings are equal') { "".should eq ""}
  it('should find two strings are equal') { "".should eql ""}
  it('should find two Strings are equal') { "".should equal ""}  # Failed
  it('should find two strings are equal') { "".should be ""}  # Failed
end  

In case of String, it will fail on "equal" and "be" statements. It is because these String data are different instances. First two test cases are comparing their values, which are the same. However, third and fourth test cases are comparing if they are the same object instance, which is not.

Array

describe 'Array' do  
  it('should find two Arrays are equal') { {:a => 1}.should eq :a => 1 }
  it('should find two Arrays are equal') { {:a => 1}.should eql :a => 1 }
  it('should find two Arrays are equal') { {:a => 1}.should equal :a => 1 }      # Failed
  it('hould find two Arrays are equal') { {:a => 1}.should be :a => 1 }         # Failed
end  

In case of Array, it will fail on "equal" and "be" statements. The reason are the same as String cases.

Conclusion

We can see that "eq" and "eql" are used to compare the object value,
while "equal" and "be" are used to compare the object_id by referencing the above result.

That's mean the compare statements of checking the object_id are using for compare the Fixnum data.

The compare statements of checking the object value are using for compare the normal data type, e.g. String, Array ...


Reference

Suzuki MilanPaak. 17 JUN 2012. RSpecのequal, eql, eq, be の違い. Retrieved from :
http://engineerflies.blogspot.hk/2012/06/rspecequal-eql-eq-be.html#.WWght9OGOi5

myronmarston. Last published at May 2017. Equality matchers. Retrieved from :
https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/equality-matchers