我有一个在控制器动作中创建的worker。 worker实例化另一个服务对象。我已经测试了worker和service对象,但我想测试控制器操作是否正确初始化了worker。我在概念上理解我应该嘲笑的东西以及这样做的语法。
我的工作人员看起来像这样:
class RepoWorker
def perform(user)
# business logic
RepositorySyncer.new(user)
end
end
我的控制器看起来像这样:
class SessionsController < ApplicationController
def create
# business logic
RepoWorker.new.async.perform(user)
redirect_to root_path
end
end
我认为我的测试应该看起来像这样,但我无法让它发挥作用。
it 'create a job to sync repos with github' do
expect(RepoWorker).to receive(:perform)
post :create, provider: :github
end
我正在使用rspec-mocks 2.14.1。
答案 0 :(得分:4)
问题是当你写
时expect(RepoWorker).to receive(:perform)
你实际上预计会发生这种情况:
RepoWorker.perform
有两种方法可以达到你想要的效果。使用存根链(https://www.relishapp.com/rspec/rspec-mocks/v/3-0/docs/message-expectations/message-chains-in-the-expect-syntax):
expect(RepoWorker).to receive_message_chain(:new, :async, :perform)
或使用any_instance(https://www.relishapp.com/rspec/rspec-mocks/v/3-0/docs/message-expectations/expect-a-message-on-any-instance-of-a-class):
expect_any_instance_of(RepoWorker).to receive(:perform)
编辑: 对于rspec 2.x,两种方法是:
worker = double
RepoWorker.stub_chain(:new, :async).and_return(worker)
expect(worker).to receive(:perform)
RepoWorker.any_instance.should_receive(:perform)
答案 1 :(得分:0)
您可以模拟RepoWorker
并确保调用某个方法。通过这种方式,您可以确保没有人删除perform
电话而不会导致任何错误 - 至少您有一个规范告诉他这不是一个聪明的举动。
所以你可以这样做:(没有经过测试,只需通过快速搜索,语法取决于您使用的精确模拟库)
it 'create a job to sync repos with github' do
RepoWorker.should_receive(:perform).at_least_once
post :create, provider: :github
end
答案 2 :(得分:0)
这就是我最终解决问题的方法。
it 'create a job to sync repos with github' do
job = double('job')
RepoWorker.stub_chain(:new, :async).and_return(job)
expect(job).to receive(:perform)
post :create, provider: :github
end