在测试控制器时,我遇到了Rails 4.0.3和rspec 2.14.1的问题。
控制器的相关部分是:
class LoginsController < ApplicationController
def sign_in
@user = User.find_by(email: params[:email])
# ... - a few other codepaths but nothing that looks for primary_phone
if params[:email]
@user.send_token
flash[:notice] = "blah blah"
end
end
User.rb是:
class User < ActiveRecord::Base
# ...
def send_token
raise 'Tried to send token to contact with no phone number' if primary_phone.nil?
SMSSender.sms(primary_phone,"Your login code is: #{generate_token}")
end
end
规范是:
require 'spec_helper'
describe LoginsController do
it "sends a token if a valid email is provided" do
@u = create(:user, primary_phone: "abc")
User.any_instance.should receive(:send_token)
post 'sign_in', email: @u.email
end
end
而且,我的用户工厂:
FactoryGirl.define do
factory :user do
name "MyString"
email "a@b.com"
end
end
当我将规范的@u = create
行更改为@u = create(:user)
时(即省略primary_phone
),我得到:
Failure/Error: post 'sign_in', email: @u.email
RuntimeError:
Tried to send token to contact with no phone number
# ./app/models/user.rb:16:in `send_token'
# ./app/controllers/logins_controller.rb:19:in `sign_in'
# ./spec/controllers/logins_controller_spec.rb:14:in `block (3 levels) in <top (required)>'
这是预期的。当我将其更改为包含primary_phone
时,我得到:
1) LoginsController sign_in sends a token if a valid email is provided
Failure/Error: User.any_instance.should receive(:send_token)
(#<RSpec::Mocks::AnyInstance::Recorder:0x007ff537ed4bd8>).send_token(any args)
expected: 1 time with any arguments
received: 0 times with any arguments
# ./spec/controllers/logins_controller_spec.rb:14:in `block (3 levels) in <top (required)>'
无法理解为何此更改会阻止规范传递。我确实在规范中的'post'之后附加了一个调试器并查看了flash是否正确(即,确保控制器中正确的代码树正在运行)并且它是。
答案 0 :(得分:4)
问题是你需要说should_receive
而不是should receive
。这是因为any_instance
。 User.any_instance.should receive
表示无论对象any_instance
返回(RSpec::Mocks::AnyInstance::Recorder
)都应该接收呼叫。当然这不是你想要的,因为该对象也与控制器实例化的实例不同。 (实际上它甚至不是User
。)因此Recorder
有一个特殊的should_receive
方法可以完成您真正想要的操作。棘手!
答案 1 :(得分:2)
您在规范中创建的User
对象与User
方法创建并发送sign_in
的{{1}}对象不同,因此您设置的期望值您错误消息中反映的send_token
上的内容将无法满足。它们都与相同的底层数据库记录相关联,但它们是不同的Ruby对象。 (注意:在您的问题的第一个版本中,您为规范显示的代码与您显示的错误不匹配,因为代码显示在@u
上设置了期望,而您的错误消息反映了对{的预期{1}}
此外,需要将之前的设置为您预期的电话(例如,在您的情况下User.any_instance
之前,如@PaulAJungwirth的评论中所述。
最后,作为@PaulAJungwirth提供的答案的替代方案,您可以使用:
@u
用你所说的期望线解决问题。