如何在 Rails 服务中存根依赖项
How can I stub a dependency in a Rails service
我有:
- 调用第 3 方的 Web 服务包装器 API (lib)
- 调用该包装器并进行一些欺骗(服务)的服务
用 VCR 测试库 class 效果很好,但我不确定如何测试该服务。具体来说,我如何在服务中存根 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 传递给构造函数。
感谢您的帮助。
更新
移至完整答案
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) 存根服务名称的常量:
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 调用正确的模拟链。
可能有更简单的方法,但代码对我来说看起来不错,所以发布它。
我有:
- 调用第 3 方的 Web 服务包装器 API (lib)
- 调用该包装器并进行一些欺骗(服务)的服务
用 VCR 测试库 class 效果很好,但我不确定如何测试该服务。具体来说,我如何在服务中存根 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 传递给构造函数。
感谢您的帮助。
更新
移至完整答案
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) 存根服务名称的常量:
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 调用正确的模拟链。
可能有更简单的方法,但代码对我来说看起来不错,所以发布它。