我正在尝试编写一个测试resque-retry重试功能的规范,我似乎无法让测试正确地命中binding.pry。有没有办法使用rspec 3测试此功能,以便我可以验证它们是否按预期运行?
这是一个请求规范,我试图通过灯具模拟实时请求,但无论我尝试什么,我似乎都无法重试。
if (Math.sqrt(number) % 1 == 0)
我正在使用resque_rspec,并试用此testing strategy。
部分规范
gem 'resque', require: 'resque/server'
gem 'resque-web', require: 'resque_web'
gem 'resque-scheduler'
gem 'resque-retry'
gem 'resque-lock-timeout'
队列作业
it 'retries it' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200)
@order_shipped_json['order']['originator_id'] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
ResqueSpec.perform_all(queue_name)
???
end
队列作业模块
class QueueHook
extend Resque::Plugins::LockTimeout
extend Resque::Plugins::Retry
extend QueueLock
extend QueueLogger
@queue = AppSettings.queues[:hook_queue_name].to_sym
@lock_timeout = 600
@retry_exceptions = [QueueError::LockFailed]
@retry_limit = 600
@retry_delay = 1
class << self
def perform(web_hook_payload_id, _whiplash_customer_id)
ActiveRecord::Base.clear_active_connections!
@web_hook_payload = WebHookPayload.find(web_hook_payload_id)
klass_constructor
@hook.process_event
end
def identifier(_web_hook_payload_id, whiplash_customer_id)
"lock:integration_hook:#{whiplash_customer_id}"
end
def after_perform_delete_webhook(_web_hook_payload_id, _whiplash_customer_id)
@web_hook_payload.destroy
end
private
...
end
end
答案 0 :(得分:2)
一些注意事项 -
1)正如其他人所提到的,您可能希望将resque
回调与其功能分开。也就是说,测试retries
正在触发,还要单独测试它们是否按预期运行。您可能希望将它们分成两个单独的测试。
2)为了检查他们是否正在开火,我认为您正在寻找RSpec 3中的class doubles。
您需要实例化double,然后引发异常(docs)。这样您就可以查看是否正在调用retries
,以及调用它们的次数(docs)。
所以,例如,
it "retries on exception n number of times" do
queue_hook = class_double("QueueHook")
expect(queue_hook).to have_received(:on_failure_log_job).exactly(n).times
allow(queue_hook).to receive(:perform).and_raise(ExceptionClass, "Exception message")
queue_hook.perform(payload_id, customer_id)
end
还有一点点,所以我无法在本地实施,但希望这可以帮助你朝着正确的方向前进。
答案 1 :(得分:1)
因此,您要测试重试的特定故障来自您实施的此挂钩。
def lock_failed(*)
raise QueueError::LockFailed
end
我们需要触发这个。 Here是插件中使用的地方。由于您正在使用锁定超时,因此我们希望存根.acquire_lock_algorithm!
。这很危险,因为这种方法是插件内部api的一部分。升级插件时请记住这一点。
it 'retries it' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200)
allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true)
@order_shipped_json['order']['originator_id'] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
ResqueSpec.perform_all(queue_name)
end
此规范现在应该失败Failure/Error: raise QueueError::LockFailed
。由于这是预期的,我们可以设定一个期望。
it 'retries it' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200)
allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true)
@order_shipped_json['order']['originator_id'] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
expect {
ResqueSpec.perform_all(queue_name)
}.to raise_error(QueueError::LockFailed)
end
除非您设置ResqueSpec.inline = true
,否则现在应该传递规范。如果您已为此规范将其设置为false。它会更容易理解。
如果resque-retry正在运行,则作业的失败应该导致作业重新入队到ResqueSpec。我们可以为此添加一个期望。 expect(ResqueSpec.queues[queue_name]).to be_present
。不是我们可以再次运营这些工作。我们嘲笑acquire_lock_algorithm!
的第二个返回值是真的,所以这次工作应该成功。
由于我们想测试计数器,可以为它们添加阅读器
module QueueLogger
attr_reader :all_attempts, :num_attempts
end
然后完成规范...
it 'retries it' do
stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200)
allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true)
@order_shipped_json['order']['originator_id'] = @provider_order
post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json
# Failing
expect {
ResqueSpec.perform_all(queue_name)
}.to raise_error(QueueError::LockFailed)
expect(ResqueSpec.queues[queue_name]).to be_present
# Retrying
ResqueSpec.perform_all(queue_name)
expect(QueueHook.num_attempts).to eq(2)
... # Whatever else you want to test.
end
如果您想要专门测试日志记录,请将其存根并设置对所调用内容的期望。应该这样做,我有一个在我自己的机器上运行的简化版本。如果没有,我们可能需要了解您的测试和Resque配置的详细信息。