【发布时间】:2010-09-23 21:31:47
【问题描述】:
class A
def initialize
@x = do_something
end
def do_something
42
end
end
如何在调用原始实现之前在 rspec 中存根 do_something(因此将 42 分配给 @x)?当然,无需更改实现。
【问题讨论】:
class A
def initialize
@x = do_something
end
def do_something
42
end
end
如何在调用原始实现之前在 rspec 中存根 do_something(因此将 42 分配给 @x)?当然,无需更改实现。
【问题讨论】:
Here's the commit which adds the feature to rspec - 这是 2008 年 5 月 25 日。你可以这样做
A.any_instance.stub(do_something: 23)
但是,rspec 的最新 gem 版本(1.1.11,2008 年 10 月)中没有这个补丁。
This ticket 表示他们出于维护原因将其拉出,但尚未提供替代解决方案。
目前看来你做不到。您必须使用 alias_method 或类似的方法手动破解该类。
【讨论】:
any_instance 创建存根,然后构建对象,然后在再次调用构造函数之前使用rspec_reset 撤消所有存根。注意 rspec_reset 没有记录,可能不受官方支持。您可以在任何对象上调用它以删除该对象的存根
我在http://pivotallabs.com/introducing-rr/找到了这个解决方案
new_method = A.method(:new)
A.stub!(:new).and_return do |*args|
a = new_method.call(*args)
a.should_receive(:do_something).and_return(23)
a
end
【讨论】:
我不知道如何在规范的模拟框架中做到这一点,但您可以轻松地将其换成 mocha 来执行以下操作:
# should probably be in spec/spec_helper.rb
Spec::Runner.configure do |config|
config.mock_with :mocha
end
describe A, " when initialized" do
it "should set x to 42" do
A.new.x.should == 42
end
end
describe A, " when do_something is mocked" do
it "should set x to 23" do
A.any_instance.expects(:do_something).returns(23)
A.new.x.should == 23
end
end
【讨论】:
或RR:
stub.any_instance_of(A).do_something { 23 }
【讨论】:
在今天最新版本的 RSpec - 3.5 中,您可以:
allow_any_instance_of(Widget).to receive(:name).and_return("Wibble")
【讨论】:
我确实喜欢 Denis Barushev 的回答。而且我只想建议一种外观上的改变,这使得new_method 变量变得不必要。 Rspec 确实对存根方法进行了处理,因此可以使用 proxied_by_rspec__ 前缀访问它们:
A.stub!(:new).and_return do |*args|
a = A.proxied_by_rspec__new(*args)
a.should_receive(:do_something).and_return(23)
a
end
【讨论】:
在 RSpec 2.6 或更高版本中,您可以使用
A.any_instance.stub(do_something: 23)
请参阅the docs 了解更多详情。 (感谢rogerdpack 指出现在这是可能的——我认为它应该得到自己的答案)
【讨论】:
要存根实例方法,您可以执行以下操作:
before :each do
@my_stub = stub("A")
@my_stub.should_receive(:do_something).with(no_args()).and_return(42)
@my_stub.should_receive(:do_something_else).with(any_args()).and_return(true)
A.stub(:new).and_return(my_stub)
end
但正如 pschneider 指出的那样,只需在 new 上返回 42 :
A.stub(:new).and_return(42) 或类似的东西。
【讨论】:
A.stub(:new).and_return(@my_stub) 每次都会返回实例存根,从而让您控制实例的创建。至于设置成员变量,我一直听说您不应该担心模拟/存根中的内部结构,只需担心公共接口。因此,只需为依赖于@x 的方法返回正确的值。我可能错了
这是一个可能不是很优雅但基本上肯定会奏效的想法:
创建一个继承您要测试的类的小类,覆盖初始化方法并调用super在在初始化中创建存根之后,如下所示:
it "should call during_init in initialize" do
class TestClass < TheClassToTest
def initialize
should_receive(:during_init)
super
end
end
TestClass.new
end
你去吧!我刚刚在我的一项测试中成功使用了它。
【讨论】:
rspec_candy gem 带有一个stub_any_instance 辅助方法,该方法在 RSpec 1 和 RSpec 2 中都有效。
【讨论】:
在我的 rspec (1.2.2) 版本中,我可以这样做:
A.should_receive(:new).and_return(42)
我知道回答原始海报可能为时已晚,但我还是回答了它以供将来参考,因为我带着同样的问题来到这里,但发现它正在使用最新的 rspec 版本。
【讨论】: