在控制器规范中测试/模拟工人

时间:2014-04-06 01:52:11

标签: ruby-on-rails ruby rspec

我有一个在控制器动作中创建的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。

3 个答案:

答案 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