Reputation: 147
I am writing some rspec examples for a plain old ruby class in my rails project and I am facing the following problem. I have this constructor:
class Server
def initialize(host='localhost',options={:port => 443, :password => '', :vpncmd_bin_path => '/usr/local/bin/vpncmd', :timeout => 5})
@host = host
@port = options[:port].present? ? options[:port] : 443
@password = options[:password].present? ? options[:password] : ''
@vpncmd_bin_path = options[:vpncmd_bin_path].present? ? options[:vpncmd_bin_path] : '/usr/local/bin/vpncmd'
@timeout = options[:timeout].present? ? options[:timeout] : 5
@hubs = {}
@hub_cache_dirty = true
@hub_password_cache = {}
end
...
end
This test example:
it "should have a default constructor that takes no argument" do
s = SoftEther::Server.new()
expect(s.host).to be_equal('localhost')
expect(s.port).to be_equal('443')
expect(s.timeout).to be_equal(5)
expect(s.vpncmd_bin_path).to be_equal('/usr/local/bin/vpncmd')
expect(s.password).to be_equal('')
end
And rspec gives me the following result with Rails 4.2.6, jruby-9.0.5.0 and 3.4.4:
1) SoftEtherSever should have a default constructor that takes no argument
Failure/Error: expect(s.host).to be_equal('localhost')
expected `"localhost".equal?("localhost")` to return true, got false
# ./spec/poro/softether_spec.rb:19:in `block in (root)'
What did I do wrong?
Upvotes: 2
Views: 661
Reputation: 2653
Just to add an edge case to Simone's answer:
If you were to freeze the strings in question, you would get the result you expected:
irb(main):001:0> 'test'.equal? 'test'
=> false
irb(main):002:0> 'test'.freeze.equal? 'test'.freeze
=> true
In Ruby 2.3, this can be done by adding
# frozen_string_literal: true
to the top of the Ruby file.
With that said, Simone is right. You should use the eq
matcher unless you truly want to test that you are using the same exact object instance. Then using equal
is in order.
Upvotes: 1
Reputation: 176362
equal?
checks whether two instances are the same. But it returns false when two strings contains the same value but refers to different objects:
"foo".equals?("foo")
# => false
What you should really use is eq()
expect(s.host).to eq('localhost')
Upvotes: 6