sheepdog
sheepdog

Reputation: 625

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

Upvotes: 0

Views: 1838

Answers (2)

arieljuod
arieljuod

Reputation: 15848

You have to do this:

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

Like it was said before, the method is called on a new User instance, not the one you set te expectation. You have to stub the "from_token" class method to return the same object you are expecting messages on, not another instance with the same id from the database.

Upvotes: 1

Sergio Tulentsev
Sergio Tulentsev

Reputation: 230531

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.

Upvotes: 1

Related Questions