受到Sandi Metz的编写测试方法(http://www.confreaks.com/videos/2452-railsconf2013-the-magic-tricks-of-testing)的启发,我试图重构Rails控制器的测试,断言它正在正确发送命令消息。
以下是申请的相关部分:
class DealsController < ApplicationController
def index
if params[:reset]
deal_filter.reset
...
class ApplicationController
def deal_filter
...
@deal_filter ||= DealFilter.new(args)
end
...
class DealFilter
def reset
...do work...
end
...
这是rspec测试:
describe DealsController do
it "should send 'reset' to the deal_filter" do
df = instance_double("DealFilter")
get :index, reset: "true"
expect(df).to receive(:reset)
end
end
不断回归的测试结果是:
1) DealsController GET index for any user params contain 'reset' should send 'reset' to the deal_filter
Failure/Error: expect(df).to receive(:reset)
(Double "DealFilter (instance)").reset(any args)
expected: 1 time with any arguments
received: 0 times with any arguments
我已经确认重置参数正在通过测试发送,并且控制器正在遵循相应的路径,但测试仍然失败。
任何人都可以提出失败的可能原因或进一步研究的资源吗?我对面向对象思想和使用Rspec的模拟相对较新。难道我误解了双打的角色吗?
谢谢你的时间!
答案 0 :(得分:1)
您需要确保双重使用。我认为这里最好的方法是将deal_filter
方法存根以返回double。
我补充说我会孤立这一点,因此它是it
区块中唯一的东西。这样可以更轻松地添加更多的预期而无需重复设置逻辑。
describe DealsController do
let(:df) { instance_double("DealFilter") }
before do
allow(controller).to receive(:deal_filter).and_return(df)
get :index, reset: "true"
end
it "should send 'reset' to the deal_filter" do
expect(df).to have_received(:reset)
end
end
答案 1 :(得分:0)
我认为您希望在index操作中的某个位置自动使用instance_double。这不是双打工作的方式。您可以创建一个double并将其用于事物,但是控制器中的代码不会(也不应该)知道关于该double的任何内容,因此不会在其上调用任何内容。
有关如何实际使用实例double的示例,请参阅this documentation。
您期望的另一个问题是您没有及早设置它。当你期望一个对象接收一个方法调用时,需要在那之后发生一些会调用该方法的东西。在您的示例中,期望接收:reset是示例的最后一行。
我建议reading up关于其他人如何使用rspec测试控制器作为一个良好的起点。