我的测试"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
答案 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的另一个实例。