[rspec-users] a MockExpectationError problem

Phillip Koebbe phillipkoebbe at gmail.com
Sun Apr 25 17:51:26 EDT 2010


  On 2010-04-25 4:25 PM, Patrick J. Collins wrote:
> On Sun, 25 Apr 2010, Phillip Koebbe wrote:
>> See http://gist.github.com/378489 for how I ended up specing a file upload.
>> This isn't the exact same situation, but maybe you will get some ideas that
>> will help. And there may be a better way, but this seems to work and is fairly
>> easy for me understand.
> Yeah, I see what you're doing, but I don't quite get how I could apply this to
> what I am doing.
>

I was just thinking that since your problem had to do with files on the 
file system getting overwritten, seeing how to someone worked around 
that problem with uploads might trigger some ideas in your mind.

> I have a method that creates a contact and then creates a photo and assigns it
> to that contact.
>
> So my problem comes from doing (in my model method):
>
> @contact.photo = Photo.create(...)
>
> ...  Although the code works fine in the real world app use, the spec fails
> because it's trying to do something with "[]=" .. which I don't get.
>

I may be mistaken, but []= looks like an array assignment, which would 
suggest to me something to do with adding an element to a collection 
somewhere.

Do you have any hooks defined that affect the creation process? Or is 
this a straight-forward, vanilla Photo.create call that goes straight 
into ActiveRecord? Maybe you should gist your spec and file.

> ----
>
> Also, I have a couple side questions--
>
> 1) is there some sort of caching done to before(:all/:each) blocks?
>
> I had a before block that set an instance variable to something, and then I
> removed it-- and was getting weird behavior, and after doing some inspecting I
> found that the instance variable was still set-- even though it was not set
> anywhere in the code...  I had to put a blank before block in there to get that
> behavior to stop...  Just wondered if this is normal?
>

I've not experienced that problem, so I can't help with this.

> 2)  I still am struggling with mock vs stub-- or I should say stub! vs.
> should_receive.  Initially I had something like this:
>
> before(:all) do
>    foo = mock_model)
>    Foo.should_receive(:find_by_name).with("bar").and_receive(foo)
> end
>
> it "blah" do
>    3.times {  @blah.do_something }
> do
>
> it "blah2" do
>    3.times { @blah.do_something }
> end
>
> (blah model)
> def do_something
>    @foo = Foo.find_by_name("bar")
> end
>
> This wasn't working, because apparently it's only good for one usage.  I was
> thinking that declating "should_receive" would mean that anytime Foo gets
> .find_by_name called on it, it will have that behavior.  I ended up changing
> that to a before(:each), and then I got errors like expected it 1 time but got
> it 3 times....
>
> So not knowing how to deal with that, I changed .should_receive to .stub! and
> then the errors went away.
>
> Not sure if that was the right thing to do in that case.
>

Use stub when you just want to provide the plumbing. Use should_receive 
when you are setting an expectation. As an example, you could do 
Photo.stub(:create) just to provide the method to avoid errors when your 
code calls it. But if you actually want to verify that your code calls 
it, then do Photo.should_receive(:create). After David gave his input a 
few weeks ago, I've adopted an approach in which I stub methods in 
before(:each), including return values where appropriate, and then put 
an expectation in an example. So I might have something like:

before(:each) do
     widget = stub_model(Widget).as_new_record
     Widget.stub(:new).and_return(widget)
end

it 'should call Widget.new' do
     Widget.should_receive(:new)
     get :new
end

it 'should render the new template' do
     get :new
     response.should render_template(:new)
end

In this example, the real code is going to call .new both times, but I'm 
setting an expectation just once (trying to follow the convention of one 
test per example). In the first example, where the expectation is set, 
I'll get a failure if .new isn't called. In the second one, no 
expectation is set, but since I'm using a stubbed model, I don't want 
the class actually calling real methods, hence the stub. I personally 
find it's easier and more logical to do it this way. Doing it like this, 
I could remove the first example and nothing else breaks and it still 
makes perfectly good sense.

Peace,
Phillip


More information about the rspec-users mailing list