我想断言,某个方法被调用N次(不多也不少),并带有特定的参数和特定的顺序.我也不想实际执行这个方法,所以首先我用allow()
作为存根.
假设我有这样的代码:
class Foo
def self.hello_three_times
Foo.hello(1)
Foo.hello(2)
Foo.hello(3)
end
def self.hello(arg)
puts "hello #{arg}"
end
end
我想测试方法hello_three_times
,它使用1、2和3作为参数调用hello
三次.(我不想在测试中真正调用hello
,因为实际上它包含副作用并且速度很慢.)
所以,如果我写这个测试
RSpec.describe Foo do
subject { Foo.hello_three_times }
it do
allow(Foo).to receive(:hello).and_return(true)
expect(Foo).to receive(:hello).with(1).once.ordered
expect(Foo).to receive(:hello).with(2).once.ordered
expect(Foo).to receive(:hello).with(3).once.ordered
subject
end
end
它通过了,但不能保证之后不会有额外的调用.例如,如果有一个错误,方法hello_three_times
实际上看起来像这样
def self.hello_three_times
Foo.hello(1)
Foo.hello(2)
Foo.hello(3)
Foo.hello(4)
end
测试仍将是绿色的.
如果我试着把它和像这样的exactly(3).times
结合起来
RSpec.describe Foo do
subject { Foo.hello_three_times }
it do
allow(Foo).to receive(:hello).and_return(true)
expect(Foo).to receive(:hello).exactly(3).times
expect(Foo).to receive(:hello).with(1).once.ordered
expect(Foo).to receive(:hello).with(2).once.ordered
expect(Foo).to receive(:hello).with(3).once.ordered
subject
end
end
它失败是因为RSpec似乎在第一个Expect之后将调用视为已完成(可能在本例中,它的工作方式是预期首先有3个调用,然后再分别有3个调用,因此总共有6个调用):
Failures:
1) Foo is expected to receive hello(3) 1 time
Failure/Error: expect(Foo).to receive(:hello).with(1).once.ordered
(Foo (class)).hello(1)
expected: 1 time with arguments: (1)
received: 0 times
有没有一种方法可以组合这样的预期,从而保证恰好有3个参数为1、2和3(有序的)的调用(不多也不少)?