Rspec - как проверить, что вложенная служба создается соответствующим образом, и в этом экземпляре вызывается соответствующий метод - PullRequest
0 голосов
/ 05 декабря 2018

Предположим, у меня есть класс, который должен вызывать службу несколько раз с разными аргументами

class MyExecutor
  def perform
    targets.each do |target|
      MyService.new(target).call
    end
  end
end

class MyService
  def initialize(target)
    @target = target
  end

  def call
    @target.do_something
  end
end

Предположим, я хочу написать тест для MyExecutor, генерируя данные, чтобы у меня было как минимум 2целей, и я хочу проверить, что служба MyService вызывается соответствующим образом для всех целей.

Когда у меня была только одна цель, я мог использовать expect_any_instance_of().to receive(:call), но тогда я не проверял конкретизацию с соответствующимиparams, а затем этот синтаксис устарел (см. комментарий здесь )

describe MyExecutor
  context 'with one target'
    it 'calls the MyService appropriately'
      expect_any_instance_of(MyService).to receive(:call)
      MyExecutor.perform
    end
  end
end

Предположим, у меня несколько целей, как я могу проверить, что MyService создается дважды, один раз скаждая соответствующая цель, и что в каждой из этих инстанцируемых служб метод call вызывается надлежащим образом Каков надлежащий недревесный способ проверить это?

Неявный вопрос: (это правильный способ решения проблемы?)

Ответы [ 2 ]

0 голосов
/ 06 декабря 2018

В синтаксисе Rspec 3.8:

describe MyExecutor do
  subject(:executor) { described_class.new }

  describe '#perform' do
    subject(:perform) { executor.perform }

    let(:target1) { instance_double('target' }
    let(:target2) { instance_double('target' }
    let(:service1) { instance_double(MyService, call: true) }
    let(:service2) { instance_double(MyService, call: true) }

    before do 
      allow(MyExecutor).to receive(:targets).and_return([target1, target2])
      allow(MyService).to receive(:new).with(target1).and_return(service1)
      allow(MyService).to receive(:new).with(target2).and_return(service2)

      perform
    end

    it 'instantiates MyService once for each target' do
      expect(MyService).to have_received(:new).with(target1).ordered
      expect(MyService).to have_received(:new).with(target2).ordered
    end

    it 'calls MyService once for each target' do
      expect(service1).to have_received(:call)
      expect(service2).to have_received(:call)
    end
  end
end

Обратите внимание, что использование .ordered позволяет указывать точный порядок операций.

Обратите внимание, что удвоение MyService .with, определенный параметр позволяетвам контролировать возвращаемое значение для этого конкретного параметра.

0 голосов
/ 05 декабря 2018

Мне кажется, я понимаю вашу потребность:

 describe MyExecutor do
   context 'with one target' do
     it 'calls the MyService appropriately' do
       target1 = double("TargetClass")
       target2 = double("TargetClass")
       allow(MyExecutor).to receive(:targets).and_return([target1, target2])

       service1 = double(MyService, call: nil)
       service2 = double(MyService, call: nil)
       expect(MyService).to receive(:new).with(target1).once.and_return(service1)
       expect(MyService).to receive(:new).with(target2).once.and_return(service2)

       MyExecutor.perform
     end
   end
 end
...