On Apr 26, 2011, at 4:02 PM, Rodrigo Rosenfeld Rosas wrote: > Ok, now I understand what is your issue. > >>>> class Foo >>>> end >>>> >>>> class Bar >>>> def self.my_foo >>>> @my_foo ||= Foo.new >>>> end >>>> def self.perform >>>> my_foo.do_something >>>> end >>>> end >>>> >>>> describe Foo do >>>> >>>> before(:each) do >>>> @stupid_mock = double('wtf') >>>> Foo.stub(:new => @stupid_mock) >>>> end >>>> >>>> it "passes here" do >>>> @stupid_mock.should_receive(:do_something).and_return('value') >>>> Bar.perform >>>> end >>>> >>>> it "fails here" do >>>> @stupid_mock.stub(:do_something => 'value') >>>> Bar.perform >>>> # double "wtf" received unexpected message :do_something with (no args) >>>> end >>>> >>>> end >>> > >> > > The first time Bar.foo is being called, it caches Foo.new. Since you stubbed > Foo.new to return a mock before running Bar.foo for the first time, this mock > is cached inside Bar, so any subsequent call will return the first created > mock object. This obviously won't happen if you run only the other spec and > that is why it passes in this case. > > This is not about passing by reference, but it is about caching Bar.my_foo. > > The only way I can think of RSpec not being affected by this is to reloading > all classes before each example, which would be both complicate and costly. > > You'll probably have to rethink your testing strategies, avoiding caching > class methods or not mocking something that could affect them, or > initializing them first before running the specs... > > Best regards, > > Rodrigo.
I see now the crux of the issue - mocks are implicitly cleared out before each example, so even though the same object is being returned, RSpec is sneakily substituting a doppelganger for @stupid_mock. This apparently wasn't the case in the last version, where the instance variable would continue to be connected to the same object. This might be intended behavior, but it feels like a bug because that memoizing behavior is so common. Because I can't set up the double in a before(:all) block due to the above behavior, the solution is to add: Bar.instance_variable_set(:@my_foo, nil) # Forcibly clear Bar's cached instance to the before(:each) block. -- matt
_______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users