Как написать модульный тест для метода, который возвращает объект в блок в RSpec

У меня есть класс, который реализует метод .call, который возвращает объект в блок, и я хотел бы узнать, как написать для этого модульный тест. Вот что у меня есть.

module A
  class B < Service
    def call(object_id:)
      @object = Something.find(object_id)
      @object.update(status: 'done')
      yield @object
    end

    def set_to_in_progress
      @object.update(status: 'in_progress')
    end
  end
end

class Service
  def self.call(*args); new.call(*args); end
end

Затем я использую это так:

A::B.call(obj) do |object|
  object.set_to_in_progress if some_other_condition?
end

Мне нужно иметь возможность написать модульный тест для метода call, который проверяет, изменился ли статус на «выполнено» или «в процессе». Вот что у меня есть:

RSpec.describe A::B, :unit do
  let(:object) { create(:something, id: 1, status: 'in_progress') }

  it 'updates the status to done' do
    described_class.call(object.id) do |???|
      ???
    end

    expect(object.status).to equal('done')
  end

  it 'updates the status to in progress' do
    described_class.call(object.id) do |???|
      ???
    end

    expect(object.status).to equal('in_progress')
  end
end

person jedi    schedule 03.10.2019    source источник
comment
Не сработает ли эта спецификация, потому что Something.find(object_id) не найдет запись, поскольку вы никогда не создаете ее в спецификации?   -  person Kris    schedule 03.10.2019
comment
@Kris Ты прав, хорошее место! Я исправил это.   -  person jedi    schedule 03.10.2019


Ответы (2)


Вы можете вернуть объект в #call:

def call(object_id:)
  @object = Something.find(object_id)
  @object.update(status: 'done')
  yield @object
  @object
end    

Затем в тесте вы можете сделать:

object = described_class.call(object.id)
expect(object.status).to eq('in_progress')
person Kris    schedule 04.10.2019

Вы ищете yield_with_args сопоставление:

specify do
  expect { |block| described_class.call(object.id, &block) }
    .to yield_with_args(object)
end

Просто заметьте, что вы смешиваете тестирование поведения (выдает object) и побочные эффекты (object было изменено).

person phil pirozhkov    schedule 23.12.2019