2016-08-28 6 views
18

resque-retry의 재시도 기능을 테스트하는 스펙을 작성하려고하는데 binding.pry를 정확하게 테스트 할 수없는 것 같습니다. rspec 3을 사용하여이 기능을 테스트 할 수있는 방법이 있습니까? 그렇다면이 기능이 의도 한대로 작동하는지 확인할 수 있습니까?resque-retry 및 Rails 4에서 재시도 및 실패를 테스트하는 방법은 무엇입니까?

이것은 요청 사양이며 설비를 통해 실시간 요청을 시뮬레이션하려고 시도하지만 어떤 작업을 시도하든 다시 시도 할 수없는 것으로 보입니다.

gem 'resque', require: 'resque/server' 
gem 'resque-web', require: 'resque_web' 
gem 'resque-scheduler' 
gem 'resque-retry' 
gem 'resque-lock-timeout' 

나는 resque_rspec를 사용하여,이 testing strategy을 시도하고있다.

일부 사양

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 

큐 작업 모듈

module QueueLogger 
    def before_perform_log_job(*args) 
    Rails.logger.info "[Resque][#{self}] running with #{args.inspect}..." 
    end 

    def on_failure_log_job(*args) 
    message = "[Resque][#{self}] failed with #{args.inspect}..." 
    run_counters 
    Rails.logger.info message_builder(message) 
    end 

    private 

    def run_counters 
    @num_attempts += retry_attempt 
    @all_attempts += retry_limit 
    end 

    def message_builder(message) 
    return message unless @num_attempts 
    return message += " Retrying (attempt ##{@num_attempts + 1})" if @num_attempts < @all_attempts 
    message += ' Giving up.' 
    message 
    end 
end 

module QueueLock 
    def loner_enqueue_failed(*args) 
    Rails.logger.info "[Resque][#{self}] is already enqueued: #{args.inspect}..." 
    end 

    def lock_failed(*) 
    raise QueueError::LockFailed 
    end 
end 
+0

예외 처리기를 사용해야합니다. – user1735921

+1

예제 사양이 있습니까? –

+0

구조 재 시도, 예외 잡기 및 코드 다시 시도 사용 안 함 – user1735921

답변

1

따라서 재시도 테스트하려는 특정 오류는 구현 한이 후크에서 비롯됩니다.

def lock_failed(*) 
    raise QueueError::LockFailed 
end 

트리거해야합니다. Here은 플러그인에서 사용됩니다. 잠금 시간 초과를 사용 중이므로 .acquire_lock_algorithm!을 스터브하고 싶습니다. 이 방법은 플러그인 내부 API의 일부이므로 위험합니다. 플러그인을 업그레이드 할 때 유의하십시오.

이 사양은 현재 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!을 조롱했습니다.

우리가 카운터를 테스트 할 수 있기 때문에

은 특히 로깅을 테스트하려면

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 

당신이 그들을 스텁 ... 그들을 위해

module QueueLogger 
    attr_reader :all_attempts, :num_attempts 
end 

을 독자를 추가 한 다음 사양을 마무리 할 수 ​​있습니다 그들이 부름받은 것에 대한 기대를 설정하십시오. 그렇게해야하는데, 내 컴퓨터에서 실행되는 단순화 된 버전이 있습니다. 그렇지 않다면 우리는 당신의 테스트와 Resque 설정에 대한 세부 사항을 들어야 할 것입니다.

1

몇 notes-

1) 다른 사람들이 언급했듯이 resque 콜백을 해당 기능과 분리해야 할 수 있습니다. 즉, retries이 실행 중인지 테스트하고, 예상대로 작동하는지 별도로 테스트하십시오. 이들을 두 개의 개별 테스트로 분리 할 수 ​​있습니다. 가 발사되는 것을 확인에 대한

2), 나는 당신이 당신은 두 번 인스턴스화 할 다음 예외 (docs)을 마련 할 필요가 RSpec에 3에 class doubles에 대한

을 찾고 생각합니다. 이렇게하면 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 

진행 공정한 조금있다, 그래서 로컬 구현할 수 없습니다, 그러나 희망이 당신이 올바른 방향으로 가고 얻을 수 있습니다.