bananabr
bananabr

Reputation: 147

RSpec be_equal not working

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

Answers (2)

will_in_wi
will_in_wi

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

Simone Carletti
Simone Carletti

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

Related Questions