0

我有:

  • 调用第 3 方 API (lib) 的 Web 服务包装器
  • 调用该包装器并进行一些处理(服务)的服务

用 VCR 测试 lib 类效果很好,但我不确定如何测试服务。具体来说,我如何在服务内部存根 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 来模拟响应。我可以写一些类似的东西,比如调用 VCR 并让服务使用它的 FooMock 吗?

不确定如何使用 Ruby 执行此操作,我习惯于将 C#/Java DI 传递给构造函数。

谢谢您的帮助。

更新

移至完整答案

4

2 回答 2

1
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')
于 2015-06-05T21:01:10.930 回答
0

@mori 提供了一个很好的起点,我最终...

1)存根服务名称的常量:

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) 在 /spec/fakes 中创建一个假的 foo 包装器:

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

这意味着在我的服务中我可以Foo.new并且它处理测试和现实生活相同(伟大的集成测试)。而且我没有在测试中设置任何需要实际实例才能正确调用 VCR 的模拟链。

可能有一种更简单的方法,但代码对我来说看起来不错,所以发布它。

于 2015-06-05T21:48:11.420 回答