间谍是查看 Resque 方法是否被触发的合适方法吗? [英] Are spies an appropriate approach to see if Resque methods are being fired?

查看:71
本文介绍了间谍是查看 Resque 方法是否被触发的合适方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

虽然简单的覆盖率报告为 100% 覆盖,但我并不满意.标记为焦点的规范我想确认所有 Resque 方法都被触发.间谍或双重身份是解决此问题的正确方法吗?

While simple coverage is reporting this as 100% covered I am not satisfied. 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?

规格

describe 'resque tasks' do
  include_context 'rake'
  let(:task_paths) { ['tasks/resque'] }

  before do
    invoke_task.reenable
  end

  # rubocop:disable all
  describe 'resque' do
    context ':setup' do
      let(:task_name) { 'resque:setup' }

      it 'works' do
        invoke_task.invoke
        expect(Resque.logger.level).to eq(1)
      end
    end

    context ':scheduler_setup' do
      let(:task_name) { 'resque:scheduler_setup' }

      it 'works' do
        expect(invoke_task.invoke).to be
      end
    end

    context ':clear', focus: true do
      let(:task_name) { 'resque:clear' }

      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
    end
  end

  describe 'jobs:work' do
    let(:task_name) { 'jobs:work' }

    it 'works' do
      expect_any_instance_of(Object).to receive(:system).with("bundle exec env rake resque:workers QUEUE='*' COUNT='#{ENV['WEB_WORKERS']}'").and_return(true)
      expect(invoke_task.invoke).to be
    end
  end
  # rubocop:enable all
end

Resque Rake 任务

require 'resque'
require 'resque/tasks'
require 'resque/scheduler/tasks'

# http://jademind.com/blog/posts/enable-immediate-log-messages-of-resque-workers/
namespace :resque do
  desc 'Initialize Resque environment'
  task setup: :environment do
    ENV['QUEUE'] ||= '*'
    Resque.logger.level = Logger::INFO
  end

  task scheduler_setup: :environment

  # see http://stackoverflow.com/questions/5880962/how-to-destroy-jobs-enqueued-by-resque-workers - old version
  # see https://github.com/defunkt/resque/issues/49
  # see http://redis.io/commands - new commands
  desc 'Clear pending tasks'
  task clear: :environment do
    queues = Resque.queues
    queues.each do |queue_name|
      puts "Clearing #{queue_name}..."
      Resque.remove_queue("queue:#{queue_name}")
    end

    puts 'Clearing delayed...'
    Resque.redis.keys('delayed:*').each do |key|
      Resque.redis.del key.to_s
    end
    Resque.redis.del 'delayed_queue_schedule'
    Resque.reset_delayed_queue

    puts 'Clearing stats...'
    Resque.redis.set 'stat:failed', 0
    Resque.redis.set 'stat:processed', 0

    puts 'Clearing zombie workers...'
    Resque.workers.each(&:prune_dead_workers)

    puts 'Clearing failed jobs...'
    cleaner = Resque::Plugins::ResqueCleaner.new
    cleaner.clear

    puts 'Clearing resque workers...'
    Resque.workers.each(&:unregister_worker)
  end
end

desc 'Alias for resque:work'
# http://stackoverflow.com/questions/10424087/resque-multiple-workers-in-development-mode
task 'jobs:work' do
  system("bundle exec env rake resque:workers QUEUE='*' COUNT='#{ENV['WEB_WORKERS']}'")
end

共享上下文

shared_context 'rake' do
  let(:invoke_task) { Rake.application[task_name] }
  let(:highline) { instance_double(HighLine) }

  before do
    task_paths.each do |task_path|
      Rake.application.rake_require(task_path)
    end
    Rake::Task.define_task(:environment)
  end

  before do
    allow(HighLine).to receive(:new).and_return(highline)
  end
end

推荐答案

标记为焦点的规范我想确认所有 Resque 方法都被触发.间谍或双重身份是解决此问题的正确方法吗?

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?

是的.这个测试中的间谍只会测试它是否收到了这些方法调用,因为它充当这些测试的 double 替身;这意味着您在此测试中不是在测试任务的行为,而是在测试任务是否具有像 Resque 这样的对象来接收这些方法调用.

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.

消息期望 将示例的期望放在开头, 在您调用被测代码之前.许多开发人员更喜欢使用行为-安排-断言(或给出时间-然后)模式来构建测试.间谍是另一种类型的测试替身,它支持这种模式,它允许您使用 have_received 预期在事后已收到消息.

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.

-- 间谍 - 基础 - RSpec Mocks - RSpec - Relish

对于您的 it 'works' 测试来说这可能是什么样子的示例

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

如下

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

注意事项:

  • allow(Resque).to receive(:remove_queue).with('queue:default') 被注释掉了,因为 allow(redis_double).to receive(:keys).with('delayed:*').and_return([]) 在我的示例代码中返回一个空数组,这意味着 queues.each 从不迭代一次,所以 Resque.remove_queue("queue:#{queue_name}") 永远不会被调用并且 "Clearing default...\n"\ 不会返回预期的输出

  • 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

此外,在这个任务中发生了很多事情,可能值得将其分解为更小的任务.

这有效地在 Resque 对象上存根每个预期的方法调用,然后在调用任务后访问双打接收那些预期的方法调用.它不测试这些任务的结果,只测试发生的方法调用并确认这些

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

正在触发方法.

参考:

这篇关于间谍是查看 Resque 方法是否被触发的合适方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆