Как я могу заглушить зависимость в сервисе Rails

Я имею:

  • оболочка веб-сервиса, которая вызывает сторонний API (lib)
  • сервис, который вызывает эту обертку и делает некоторую путаницу (сервис)

Тестирование класса lib с помощью VCR прекрасно работает, но я не уверен, как протестировать сервис. В частности, как я могу заглушить вызов API внутри службы?

class GetBazsForBars
  def self.call(token)
    bazs = Foo.new(token).bars

    # do some other stuff
    bazs
  end
end

И тест:

require 'rails_helper'

RSpec.describe GetBazsForBars, type: :service do
  describe ".call" do
    let(:token) { Rails.configuration.x.test_token }
    let(:bazs)  { GetBazsForBars.call(token) }

    it { expect(bazs.any?).to eq(true) }
  end
end

Я предпочел бы не переходить в Foo на службу.

В Payola автор использует StripeMock для подведения итогов ответов. Могу ли я написать что-то подобное, например, FooMock, который вызывает видеомагнитофон и использует сервис вместо этого?

Не уверен, как это сделать с Ruby, я привык к C# / Java DI, передавая конструкторам.

Спасибо за помощь.

Обновить

Перешел на полный ответ

2 ответа

Решение
foo = double(bars: 'whatever')
allow(Foo).to receive(:new).with(:a_token).and_return foo

или же

allow(Foo).to receive(:new).with(:a_token)
  .and_return double(bar: 'whatever')

@mori обеспечил хорошую отправную точку, и я закончил...

1) заглушка const имени сервиса:

require 'rails_helper'

RSpec.describe GetBazsForBars, type: :service do
  describe ".call" do
    before { stub_const("Foo", FakeFoo) } # <-- added this

    let(:token) { Rails.configuration.x.test_token }
    let(:bazs)  { GetBazsForBars.call(token) }

    it { expect(bazs.any?).to eq(true) }
  end
end

2) создание поддельной оболочки foo в /spec/fakes:

class FakeFoo < Foo
  def bars
    VCR.use_cassette("foo_bars") do
      super()
    end
  end
end

Это означает, что в моем служении я могу просто Foo.new и он обрабатывает тест и реальную жизнь одинаково (отличный интеграционный тест). И у меня не было никаких цепочек насмешек в тесте, которые потребовали бы реального экземпляра для правильного вызова VCR.

Там может быть более простой способ, но код выглядит довольно хорошо для меня, так что отправьте его.

Другие вопросы по тегам