Rspec - 如何测试嵌套服务是否已正确实例化以及是否在此实例上调用了适当的方法
Rspec - how to test that a nested service is instanciated appropriately and the appropriate method is called on this instance
假设我有一个 class 应该使用不同的参数多次调用服务
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)
但后来我并没有真正用适当的参数测试实例化,然后这个语法就被弃用了 (cf comment here)
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
方法是适当地调用测试这个的正确的非弃用方法是什么?
隐式问题:(这是解决问题的正确方法吗?)
我想我理解你的需求:
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
在 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
特定参数允许您控制该特定参数的 return 值。
假设我有一个 class 应该使用不同的参数多次调用服务
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)
但后来我并没有真正用适当的参数测试实例化,然后这个语法就被弃用了 (cf comment here)
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
方法是适当地调用测试这个的正确的非弃用方法是什么?
隐式问题:(这是解决问题的正确方法吗?)
我想我理解你的需求:
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
在 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
特定参数允许您控制该特定参数的 return 值。