Are spies an appropriate approach to see if Resque methods are being fired?

戏子无情 提交于 2019-12-02 12:57:56

The spec marked as focus I would like to confirm that all of the Resque methods are being fired. Is a spy or a double the right approach for this?

Yes. A Spy in this test would only be testing that it received those methods calls, since it is acting as a double stand-in for those tests; meaning you are not testing the behaviour of task in this test, you are testing that the task has an object like Resque receiving those method calls.

Spies

Message expectations put an example's expectation at the start, before you've invoked the code-under-test. Many developers prefer using an act-arrange-assert (or given-when-then) pattern for structuring tests. Spies are an alternate type of test double that support this pattern by allowing you to expect that a message has been received after the fact, using have_received.

-- Spies - Basics - RSpec Mocks - RSpec - Relish

An example of what this might look like for your it 'works' test

it 'works' do
  expect(Resque).to receive(:remove_queue).with('queue:default').and_return(true)
  expect { invoke_task.invoke }.to output(
    "Clearing default...\n"\
    "Clearing delayed...\n"\
    "Clearing stats...\n"\
    "Clearing zombie workers...\n"\
    "Clearing failed jobs...\n"\
    "Clearing resque workers...\n"
  ).to_stdout
end

Is as follows

RSpec.describe "have_received" do
  it 'works' do
    Rake::Task.define_task(:environment)
    invoke_task = Rake.application['resque:clear']

    redis_double = double("redis")
    allow(redis_double).to receive(:keys).with('delayed:*').and_return([])
    allow(redis_double).to receive(:del).with('delayed_queue_schedule').and_return(true)
    allow(redis_double).to receive(:set).with('stat:failed', 0).and_return(true)
    allow(redis_double).to receive(:set).with('stat:processed', 0).and_return(true)

    allow(Resque).to receive(:queues).and_return([])
    allow(Resque).to receive(:redis).and_return(redis_double)
    # allow(Resque).to receive(:remove_queue).with('queue:default') #.and_return(true)
    allow(Resque).to receive(:reset_delayed_queue) #.and_return(true)
    allow(Resque).to receive(:workers).and_return([])

    cleaner_double = double("cleaner")
    allow(Resque::Plugins::ResqueCleaner).to receive(:new).and_return(cleaner_double)
    allow(cleaner_double).to receive(:clear).and_return(true)

    expect { invoke_task.invoke }.to output(
      # "Clearing default...\n"\
      "Clearing delayed...\n"\
      "Clearing stats...\n"\
      "Clearing zombie workers...\n"\
      "Clearing failed jobs...\n"\
      "Clearing resque workers...\n"
    ).to_stdout

    expect(redis_double).to have_received(:keys)
    expect(redis_double).to have_received(:del)
    expect(redis_double).to have_received(:set).with('stat:failed', 0)
    expect(redis_double).to have_received(:set).with('stat:processed', 0)

    expect(Resque).to have_received(:queues)
    expect(Resque).to have_received(:redis).at_least(4).times
    # expect(Resque).to have_received(:remove_queue).with('queue:default')
    expect(Resque).to have_received(:reset_delayed_queue)
    expect(Resque).to have_received(:workers).twice

    expect(Resque::Plugins::ResqueCleaner).to have_received(:new)
    expect(cleaner_double).to have_received(:clear)
  end
end

Notes:

  • The allow(Resque).to receive(:remove_queue).with('queue:default') is commented out since allow(redis_double).to receive(:keys).with('delayed:*').and_return([]) returns an empty array in my example code, meaning that queues.each never iterates once, so Resque.remove_queue("queue:#{queue_name}") is never called and "Clearing default...\n"\ is not return for the expected output

  • Also, there is a lot happening in this one task, and might be worthwhile breaking it down into smaller tasks.

This effectively stubs each of the expected method calls on the Resque object and then accesses after task has been invoked that the doubles receive those expected method calls. It does not test the outcomes of those tasks, only that method calls occurred and confirms those

methods are being fired.

References:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!