sheepdog sheepdog - 2 months ago 13
Ruby Question

Rspec: object isn't receiving method call from class method test

My test

"should call #logout_all"
is failing with

expected: 1 time with any arguments
received: 0 times with any arguments


but when I call
User.verify_from_token
directly in the
rails console
, I can see that
#logout_all
is being called (I added a
puts
statement to
#logout_all
)

RSpec.describe User, type: :model do
describe ".verify_from_token" do
let(:user) {FactoryGirl.create(:user, verified: false)}

it "should return the user if found" do
token = user.to_valid_token
expect(User.verify_from_token token).to eq(user)
end

it "should verify the user" do
token = user.to_valid_token
User.verify_from_token token
expect(user.reload.verified).to eq(true)
end

it "should call #logout_all" do
token = user.to_valid_token
expect(user).to receive(:logout_all)
User.verify_from_token token
end
end
end


class User < ApplicationRecord

...

def self.verify_from_token token
user = from_token token
if user
user.update_attribute(:verified, true)
user.logout_all
user
else
nil
end
end

...
def logout_all
update_attribute(:token_timestamp, Time.now)
end
end


If I rework the test slightly, it works fine.

it "should call #logout_all" do
token = user.to_valid_token
t1 = user.token_timestamp
User.verify_from_token token
expect(t1 < user.reload.token_timestamp).to eq(true)
end

Answer

The problem is that you set expectation on one user, but method call happens on another user. This one.

user = from_token token

You didn't show implementation of from_token, but I'm willing to bet that it loads user from database. Now, there may be only one user in the database and, logically, these two variables represent the same entity. But physically, they're still two different objects in memory. So, naturally, the expectation is not met.

Comments