在我实际操作的简化示例中,假设我有 2 次对数据库的调用:
Repo.add( something_stringy )
Repo.remove( something_floaty )
我想对数据库调用使用 mock,因为真正的调用将在别处进行测试:
let(:repo){
repo = double("Repo")
repo.should_receive(:add).with(instance_of(String))
repo.should_receive(:remove).with(instance_of(Float))
repo
}
before { FakeKlass.const_set :Repo, repo }
这一切都很好,但现在如果我将调用包装在一个事务中,我会有点难过:
Repo.transaction do
# ... some error checking in here somewhere...
Repo.add( something_stringy )
Repo.remove( something_floaty )
end
因为如果我编写一个接收 transaction
的 mock,它会收到调用,但 block 中的所有内容都不会被调用,我得到:
expected: 1 time received: 0 times
对于所有其他模拟。谁能告诉我应该如何编写规范来处理这个问题?我已经尝试阅读 RSpec 书中关于 around(:each)
的相关页面,但对我来说那是一团糟。
非常感谢任何帮助。
最佳答案
您可以使用#and_yield
从期望链中产生 yield :
repo.should_receive( :transaction ).and_yield
您也不需要在 Repo 类上设置一个 double 来 stub 方法。例如,您的设置可以这样写:
before( :each ) do
Repo.should_receive( :transaction ).and_yield
Repo.should_receive( :add ).with( instance_of(String) )
Repo.should_receive( :remove ).with( instance_of(Float) )
end
您还可以考虑使用 stub
而不是 should_receive
,因为它不会设置期望:
before( :each ) do
Repo.stub( :transaction ).and_yield
Repo.stub( :add )
Repo.stub( :remove )
end
一般来说,当您想要测试两个对象之间的交互时,您应该只使用should_receive
。我个人的经验法则是,如果它出现在before
中,则使用stub
;如果它在示例中,尤其是具有特定值,请使用 should_receive
。
关于ruby - 用 RSpec 包裹在 block 中的测试方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5958475/