[rspec-users] Class mocking

Pat Maddox pat.maddox at gmail.com
Fri Feb 27 12:25:58 EST 2009


On Fri, Feb 27, 2009 at 9:08 AM, Marcus Roberts
<M.Roberts at nittygritty.net> wrote:
>
>
>>Unless RSpec is doing some magic under the hood that I'm not aware of,
>>this is expected behavior - you're reassigning the constant value of
>>MachineInstance.
>
>>What you really want to do is mock/stub directly on MacineInstance.  e.g.
>
>>MachineInstance.should_receive(:create).and_return @mock_machine
>
> If we did that, would that stub/mock carry over into other spec files run
> later by autospec, which is what we're seeing.

No, because RSpec keeps track of partial mocks (mocks/stubs on "real"
objects) and clears them out at the end of the example run.


> I can see we're changing the definition of MachineInstance in the spec we do
> that in, but should that carry over to later specs?

Yes.  This is a Ruby thing, not an RSpec thing.  Same as if you were to do
MachineInstance = SomeOtherMachineInstance

where SomeOtherMachineInstance is a class that you defined.  You're
reassigning a constant.  Why would RSpec know or care when you do
that?

Put another way, while RSpec knows when you create a mock object, it
has no clue when/if you assigned it to something, and it certainly
doesn't know the previous value.

The built-in framework recognizes that your intent when partially
mocking an object is to use it within a certain, small scope (an
example).  It then politely cleans up after itself.  If you work
within those parameters, you'll see the behavior that you want.

If you _really_ want to just assign the constant (and I don't see why
you would...mocking methods on it directly works fine), you can store
the constant's value in a before and reset it in after:

describe "blah" do
  before(:each) do
    @klass = MachineInstance
    MachineInstance = mock('mi')
  end

  ...

  after(:each) do
    MachineInstance = @klass
  end
end

Pat


More information about the rspec-users mailing list