jpa*_*kal 5 ruby constructor rspec stubbing rr
所以我有一些代码,大致简化,看起来像这样:
class B
def initialize opts
@opts = opts
end
end
class A
def initialize opts
# defaults etc applied to opts
@b = B.new opts
end
end
Run Code Online (Sandbox Code Playgroud)
换句话说,当我使用选项初始化A时,它会创建一个B并将一组修改过的选项传递给它.
我想测试B.new得到正确的论点.现在,我正在这样做,使用RSpec/RR:
@b = Object.new
# stub methods on @b here
stub(B).new { |options|
options[:foo].should == 'whatever'
@b
}
A.new({:foo => 'whatever'})
Run Code Online (Sandbox Code Playgroud)
但这有两个问题.
首先,我无法B使用实际选项实例化实际副本.如果我在块中调用B.new,它会调用存根版本并循环直到堆栈弹出.我可以@b = B.new在存根之前设置,但我不知道将要传递的选项,从而击败测试点.
(并且在有人打电话给我之前:是的,在严格的单元测试教条中,A的测试应该在B中删除任何方法,并且需要大量存根意味着你的代码首先是坏的.)
其次,should在测试设置中,而不是在it ... do ... end之后的单独块中,感觉是错误的.但由于我不能创造一个实际的B(见上文),我也无法真正询问它的建设后状态.
有任何想法吗?
在should从语法马克-安德烈·Lafortune的答案出现在RSpec中3.下列被弃用expect的语法似乎不过工作,:
expect(B).to receive(:new).with(foo: 'whatever')
Run Code Online (Sandbox Code Playgroud)
请注意,如果要B.new返回特定实例(例如,测试双精度),可以使用and_return:
b = instance_double(B)
expect(B).to receive(:new).with(foo: 'whatever').and_return(b)
Run Code Online (Sandbox Code Playgroud)
你可以写类似的东西B.should_receive(:new).with({:foo => 'whatever'})。
就我个人而言,我避免存根/嘲笑,而宁愿测试行为;事实上,B使用给定的一组选项创建一个新的选项是依赖于实现的,我不会直接测试它。