Тестирование задания сервисного объекта с помощью rspec

У меня следующая работа:

class Test::MooJob < ApplicationJob
  queue_as :onboarding

  def perform
     avariable = Test::AragornService.build("a").call
     if avariable.status == true
        puts "job succeeded"
     end
  end
end

а сервис выглядит так:

module Test
  class AragornService

    def self.build(x)
      self.new(x)
    end

    def initialize(x)
      @x = x
    end

    def call
      10.times do
        Rails.logger.info @x
      end

      return ServiceResult.new :status => true, :message => "Service Complete", :data => @x

    rescue => e
      Bugsnag.notify(e, :context => 'service')
      return ServiceResult.new :status => false, :message => "Error occurred - #{e.message}"
    end

  end
end

Я пытаюсь проверить это со следующей спецификацией:

# bundle exec rspec spec/jobs/test/moo_job_spec.rb
require "rails_helper"

describe Test::MooJob do
  subject(:job) { described_class.perform_later }
  subject(:job_now) { described_class.perform_now }

  let(:key) { "a" }

  it 'queues the job' do
    ActiveJob::Base.queue_adapter = :test
    expect { job }.to have_enqueued_job(described_class)
      .on_queue("onboarding")
  end

  it 'calls the aragorn service once' do
    allow(Test::AragornService.new(key)).to receive(:call).and_return(ServiceResult.new(:status => true))
    expect_any_instance_of(Test::AragornService).to receive(:call).exactly(1).times
    job_now
  end

end

Почему это значение avariable продолжает возвращать nil. Я получаю следующую ошибку «undefined method` status 'for nil: NilClass »

однако, когда я возвращаю простое логическое значение,

разрешить (Test :: AragornService.new (key)). получить (: call) .and_return (true)

Устанавливает для переменной значение true

вот класс ServiceResult:

class ServiceResult
  attr_reader :status, :message, :data, :errors

  def initialize(status:, message: nil, data: nil, errors: [])
    @status = status
    @message = message
    @data = data
    @errors = errors
  end

  def success?
    status == true
  end

  def failure?
    !success?
  end

  def has_data?
    data.present?
  end

  def has_errors?
    errors.present? && errors.length > 0
  end

  def to_s
    "#{success? ? 'Success!' : 'Failure!'} - #{message} - #{data}"
  end

end

person EnderWiggins    schedule 19.05.2017    source источник


Ответы (1)


Это потому, что вы просто устанавливаете ожидания для несвязанного экземпляра Test::AragornService в своей спецификации:

allow(Test::AragornService.new(key)).to  
   receive(:call).and_return(ServiceResult.new(:status => true))

Это никак не повлияет на экземпляр, созданный Test::AragornService.build

class Test::MooJob < ApplicationJob
  queue_as :onboarding

  def perform
     avariable = Test::AragornService.build("a").call
     if avariable.status == true
        puts "job succeeded"
     end
  end
end

Вы можете решить эту проблему, заглушив Test::AragornService.build, чтобы вернуть двойной:

double = instance_double("Test::AragornService")
allow(double).to receive(:call).and_return(ServiceResult.new(status: true))

# bundle exec rspec spec/jobs/test/moo_job_spec.rb
require "rails_helper"

describe Test::MooJob do
  let(:perform_later) { described_class.perform_later }
  let(:perform_now ) { described_class.perform_now }
  let(:service) { instance_double("Test::AragornService") }

  before do
     # This injects our double instead when the job calls Test::AragornService.build
     allow(Test::AragornService).to receive(:build).and_return(service)
  end

  it 'queues the job' do
    # this should be done in `rails_helper.rb` or `config/environments/test.rb` not in the spec!
    ActiveJob::Base.queue_adapter = :test
    expect { perform_later }.to have_enqueued_job(described_class)
      .on_queue("onboarding")
  end

  it 'calls the aragorn service once' do
    expect(service).to receive(:call).and_return(ServiceResult.new(status: true))
    perform_now
  end
end
person max    schedule 19.05.2017
comment
Устранение этой ошибки сейчас .. 1) Test :: MooJob вызывает службу aragorn один раз. Ошибка / ошибка: ожидайте (Test :: AragornService). Для получения (: call) Test :: AragornService не реализует: call - person EnderWiggins; 20.05.2017
comment
Вы устанавливаете ожидание для класса Test::AragornService - вы должны установить его для двойника, который вы передаете. expect(double).to receive(:call) - person max; 20.05.2017