我最近在 Ruby 2.0、Rails 4 和 Rspec 2.13.1 中发现了这种奇怪的行为
当我使用ClassName.any_instance.stub(:method_name)
stub 实例方法时,它会正确 stub 和我创建的过去的实例。但是,当我通过更改返回值重新设置它时,旧实例返回旧的 stub 值,而不是新的 stub 值。
例如,我有这个虚拟类定义
class A
def test(x)
return x
end
end
这个测试描述了行为:
it 'strange stubbing behavior' do
inst = A.new
inst.test(1).should eq 1 #passes
A.any_instance.stub(:test).and_return(10)
inst.test(0).should eq 10
A.any_instance.unstub(:test) #has no effect
A.any_instance.stub(:test).and_return(100)
inst.test(0).should eq 100 #expects 100, got 10
A.any_instance.stub(:test) do |a|
a + 2
end
inst.test(3).should eq 5 #also fails # also got 10
end
为什么 rspec 会这样?这是定义的行为吗?如果是这样,那么重新启动旧实例的正确方法是什么。或者这是一个错误?
编辑:在其他人给出“质疑问题”的答案之前,我想指出,我确实通过重新思考规范并重新组织它们解决了我最初的问题。然而,我仍然很好奇为什么 RSpec 会这样表现
最佳答案
简而言之,当您使用 any_instance.unstub
在实例上调用 stub 时,RSpec 确实不会取消 stub 现有实例。同样,正如您所发现的,使用 any_instance.stub
进行 stub 操作将不适用于之前 stub /调用的实例。
但是,如果您不调用或显式取消 stub 现有实例,则任何带有 any_instance
的新 stub
都将在该实例上按预期工作。例如,对您的示例进行以下修改即可工作。
it 'strange stubbing behavior' do
inst = A.new
inst.test(1).should eq 1 #passes
A.any_instance.stub(:test).and_return(10)
# SKIP THE INVOCATION SO TEST WILL PASS
# inst.test(0).should eq 10
A.any_instance.unstub(:test) #has no effect (on existing instances)
A.any_instance.stub(:test).and_return(100)
inst.test(0).should eq 100 #expects 100, got 10
inst.unstub(:test) # UNSTUB INSTANCE SO TEST WILL PASS
A.any_instance.stub(:test) do |a|
a + 2
end
inst.test(3).should eq 5 #also fails # also got 10
end
不确定这是否是预期的行为,但提交了 issue为了它。 RSpec Cucumber 测试,可在 https://www.relishapp.com/rspec/rspec-mocks/docs/method-stubs/stub-on-any-instance-of-a-class#any-instance-unstub 查看,仅测试 unstub
是否适用于新实例。
(向@Theresa Luu 表示感谢,感谢她在这方面的帮助。)
关于ruby-on-rails - rspec any_instance stub 不会重新启动旧实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18092601/