I''m having trouble using stubs to intercept method calls in the object constructor. Here''s some code with a failing example: class Test2 attr_accessor :msg def initialize @msg = sayhi end def sayhi "hi" end end describe Test2, "stubbing methods used during object construction" do it "should assign the stub value to the instance variable" do Test2.stub!(:sayhi).and_return("bye") Test2.new.msg.should == "bye" end end (full test-case at https://gist.github.com/878911) What should I do to make this work?!? Thanks, Andy -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20110320/434e56b3/attachment-0001.html>
PS: I''m using rspec/rspec-mocks 2.5, Ubuntu 10.10, Ruby 1.8.7 -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20110320/f541e686/attachment.html>
OK - I got this working using mocha and the ''any_instance'' method. A gist with working examples is here: https://gist.github.com/879029 It looks like rspec mocks had an ''any_instance'' method, but it was removed because it promoted ''bad practice''. I''m curious to understand how ''any_instance'' promotes bad practice. I found it useful in my situation, to stub out slow network code that crushed my test performance. - Andy -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20110320/85e52fc0/attachment.html>
On Mar 20, 2011, at 9:38 PM, andyl wrote:> OK - I got this working using mocha and the ''any_instance'' method. > > A gist with working examples is here: https://gist.github.com/879029 > > It looks like rspec mocks had an ''any_instance'' method, but it was removed because it promoted ''bad practice''. > > I''m curious to understand how ''any_instance'' promotes bad practice. I found it useful in my situation, to stub out slow network code that crushed my test performance. > > - AndyA class in Ruby is an object. When you call Test2.stub(:sayhi), you are defining a stub method on the object that is the Test2 class. This class object manufactures instances, whose methods are the instance methods defined by Test2. So basically you were defining the stub on a completely different object than you thought you were. To answer your question, any_instance was rejected for a long time because it does not align with the RSpec team''s opinion of making dependencies explicit. That said, any_instance will make it into an upcoming release. Not because it''s a good idea ;) but because so many people have clamored for it and frequently use mocha primarily for that feature. Pat
On Mar 20, 2011, at 11:38 PM, andyl wrote:> OK - I got this working using mocha and the ''any_instance'' method. > > A gist with working examples is here: https://gist.github.com/879029 > > It looks like rspec mocks had an ''any_instance'' method, but it was removed because it promoted ''bad practice''.It was never released, and was removed because the patch was incomplete in retrospect. There is an open issue on this right now, with a patch in progress that I hope to include in the next release, assuming it is ready when that release is ready to go.> I''m curious to understand how ''any_instance'' promotes bad practice. I found it useful in my situation, to stub out slow network code that crushed my test performance.In general, we want test code to be as narrow and precise as possible. This means we should control which objects we are dealing with at any moment. any_instance is a bandaid for a situation in which the design makes it difficult to get a handle on a specific instance. If we''re actually doing TDD this should never happen, but sometimes we use frameworks like ActiveRecord, which provides two different objects in this scenario: widget = Factory(:widget) found_widget = Widget.find(widget.id) These two objects ^^ have the same attributes, but are not the same object. This means that stubbing methods on widget does not have any impact on found_widget. In this case, any_instance saves the day, but it leaves open some holes in tests. Consider: order = Factory(:order) Order.any_instance.should_receive(:confirm) put :confirm, :order_id => order.id If the examples and code change over time such that there are more than one order at play and the wrong one receives confirm(), this example will still pass. FYI - ActiveRecord will soon have an identity map, which means that this code will work: order = Factory(:order) order.should_receive(:confirm) put :confirm, :order_id => order.id This is a much better situation as it is very precise. HTH, David
Pat and David - Thanks for taking the time to explain this. Look forward to seeing any_instance in rspec/mocks. And I will try to use it as little as possible! ;-) - Andy -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20110323/0a0432f4/attachment.html>