间谍是否适合查看Resque方法是否被解雇?

虽然简单的报道报道这是100%覆盖我不满意。 标记为焦点的规范我想确认所有Resque方法都被触发。 这是一个间谍还是双人的正确方法?

规格

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方法都被触发。 这是一个间谍还是双人的正确方法?

是。 这个测试中的间谍只会测试它接收到的那些方法调用,因为它是这些测试的double替代品; 意味着你没有在这个测试中测试任务的行为,你正在测试该任务有一个像Resque这样的对象接收那些方法调用。

间谍

在您调用被测代码之前, 消息期望在开始时提供了示例的期望。 许多开发人员更喜欢使用act-arrange-assert(或者when-when-then)模式来构建测试。 间谍是一种替代类型的测试双重支持此模式,允许您使用have_received在事后接收消息。

– 间谍 – 基础 – RSpec模拟 – RSpec – 津津乐道

这可能是你的it 'works'测试的一个例子

 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"\不返回对于预期的产出

  • 此外,在这一项任务中发生了很多事情,并且可能值得将其分解为更小的任务。

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

方法正在被解雇。

参考文献:

  • 间谍 – 基础知识 – RSpec模拟 – RSpec – 津津乐道
  • 允许消息 – 基础 – RSpec模拟 – RSpec – 津津乐道
  • 仔细研究测试间谍