Starkers
Starkers

Reputation: 10551

What does rspec's eq method actually test for?

I'm a bit confused:

class SessionsController < ApplicationController
    def new
        @user = User.new
    end
end

I would have thought that all three of the following expectations would pass:

require 'spec_helper'

describe SessionsController do
    describe '#new' do
        let(:user) { FactoryGirl.build(:user, name: nil, email: nil, password: nil, password_confirmation: nil)}
        before { get :new }

        it { expect(assigns(:user)).to eq user }

        it { expect(assigns(:user)).to eq User.new }

        it "should assign stubbed user" do
            assigns(:user).should eq user
        end
    end
end

And yet I get this: FFF

Failures:

  1) SessionsController#new should eq #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil>
     Failure/Error: it { expect(assigns(:user)).to eq user }

       expected: #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil>
            got: #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil>

       (compared using ==)

       Diff:
     # ./spec/controllers/sessions_controller_spec.rb:8:in `block (3 levels) in <top (required)>'

  2) SessionsController#new should eq #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil>
     Failure/Error: it { expect(assigns(:user)).to eq User.new }

       expected: #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil>
            got: #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil>

       (compared using ==)

       Diff:
     # ./spec/controllers/sessions_controller_spec.rb:10:in `block (3 levels) in <top (required)>'

  3) SessionsController#new should assign stubbed user
     Failure/Error: assigns(:user).should eq user

       expected: #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil>
            got: #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil>

       (compared using ==)

       Diff:
     # ./spec/controllers/sessions_controller_spec.rb:13:in `block (3 levels) in <top (required)>'

I mean what? The Diff section is even empty. If I was using the be matcher I'd understand, but I'm using eq, so what's going on?

Upvotes: 0

Views: 139

Answers (2)

Steve
Steve

Reputation: 15736

In ActiveRecord two model objects are considered equal if they have the same class and the same non-nil primary key values.

So if two identical objects have nil id values they are not equal.

See https://github.com/rails/rails/blob/master/activerecord/lib/active_record/core.rb#L290

That may seem odd but it makes sense if you consider that those two objects if they were ever saved would be allocated two different id values by the database. So until their id of an ActiveRecord model object is allocated it cannot be compared meaningfully with another.

Upvotes: 1

tpbowden
tpbowden

Reputation: 2090

Try comparing user.attributes using the eq method instead and it should pass.

Upvotes: 0

Related Questions