我有以下rspec:
context 'when there is an incoming error' do
it 'should update status of url to error' do
url = create(:url)
error_params = {error: 'whatever', url_id : url.id}
expect(url).to receive(:set_error)
post :results, error_params
end
end
结果动作如下:
def results
url = Url.find(url_id: params['url_id'])
if params.key?('error') && !params['error'].blank?
url.set_error
end
end
如果我这样做,测试不会通过:
expected: 1 time with any arguments
received: 0 times with any arguments
但是,如果我改为:
expect_any_instance_of(Url).to receive(:set_error)
。
它过去了。我只有一个网址,所以我不确定发生了什么。
答案 0 :(得分:1)
当您创建to receive
期望时,它会连接到特定的Ruby对象。
调用results
操作时,它会实例化 new url
对象。它表示您在Rspec示例中调用期望的相同数据库对象。但它不是同一个Ruby对象 - 它是一个带有(可能)相同数据的新对象。所以期望失败了。
举例说明:
describe ".to_receive" do
it "works on Ruby objects" do
url = Url.create(:url)
same_url = Url.find(url.id)
expect(url).to_not receive(:to_s)
same_url.to_s
end
end
要(稍微)获得您可以使用any_instance
的所需行为并更改控制器,以便将url对象分配给实例变量。通过这种方式,您可以更轻松地检查url对象:
# Change your action so that it saves the url object as an instance variable
def results
@url = Url.find(url_id: params['url_id'])
if params[:error].present?
@url.set_error
end
end
# Change your spec to look at the assigned variable
context 'when there is an incoming error' do
it 'should update status of url to error' do
url = create(:url)
error_params = {error: 'whatever', url_id: url.id}
expect_any_instance_of(Url).to receive(:set_error)
post :results, error_params
expect(assigns(:url)).to eq(url)
end
end
由于assigns
只允许您在执行控制器操作后检查指定的ivar ,因此您无法使用它来创建接收期望。