Rspec:对象没有从类方法测试接收方法调用

时间:2016-09-09 08:16:30

标签: ruby-on-rails ruby rspec

我的测试"should call #logout_all"失败

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

但是当我直接在User.verify_from_token中致电rails console时,我发现正在调用#logout_all(我向puts添加了#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

如果我稍微修改测试,它可以正常工作。

 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

2 个答案:

答案 0 :(得分:1)

问题在于您为一个用户设置了期望值,但方法调用在另一个用户上进行。这个。

user = from_token token

您没有显示from_token的实现,但我愿意打赌它会从数据库加载用户。现在,数据库中可能只有一个用户,从逻辑上讲,这两个变量代表同一个实体。但在物理上,它们仍然是记忆中的两个不同对象。所以,很自然地,没有达到预期。

答案 1 :(得分:1)

你必须这样做:

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

就像之前所说的那样,该方法是在一个新的User实例上调用的,而不是你设置的那个实例。您必须存根“from_token”类方法以返回您期望消息所在的同一对象,而不是数据库中具有相同ID的另一个实例。