[rspec-users] How to mock an object defined in the before_filter function?

Evgeny Bogdanov evgeny.bogdanov at gmail.com
Wed Feb 25 17:40:51 EST 2009


The function to specify and specification for it are below.

Comment.stub!(:find).and_return(@comment)
does what I need.
However, it strongly depends on the implementation of find_comment
function,
and if I change it to, let's say, this one:
    def find_comment
       @space = Space.find(1)
       @comment = @space.comment
     end
my spec will fail. Moreover, in my spec I'm checking if the
destroy.rjs is returned on request,
and I don't care about @comment and find_comment. Thus, I would like
just to mock the whole
object @comment for the function "destroy" like it is done with
assigns for view specs, so that my spec doesn't depend on it at all.

Best,
Evgeny
PS. Sorry for bother

@comment = Space.comment, the test will fail.

before_filter :find_comment

     def find_comment
       @comment = Comment.find(:first, :conditions => ['id= ?',params
[:comment_id]])
     end

  def destroy
    @destroy_id = @comment.id #to be used in rendering partial
    @comment.destroy

    respond_to do |format|
      format.js
    end
  end

describe CommentsController, "while deleting a comment" do
  it "should render destroy.rjs in case of success" do

    # stub find_comment call
    @comment = mock_model(Comment)
    @comment.stub!(:id).and_return(1)
    @comment.stub!(:destroy).and_return(:true)

    Comment.stub!(:find).and_return(@comment)

    request.env["HTTP_ACCEPT"] = "application/javascript"
    post :destroy, :comment_id => 1, :item_id => 1, :item_type =>
"Space"

    response.should render_template("destroy")
  end
end


On Feb 25, 11:42 am, Pat Maddox <pat.mad... at gmail.com> wrote:
> Can you show your spec?  I'm not sure why you're using assigns in the
> controller spec.  David explained that it doesn't work like that.
> Your spec should look something like
>
> it "should destroy the record" do
>   mock_comment = stub_model Comment
>   Comment.stub!(:find).and_return mock_comment
>   mock_comment.should_receive(:destroy)
>   delete :destroy, :id => mock_comment.to_param
> end
>
> Pat
>
> On Wed, Feb 25, 2009 at 1:57 AM, Evgeny Bogdanov
>
> <evgeny.bogda... at gmail.com> wrote:
> > Thank you, David!
> > One small follow-up question.
> > Is there is a way to mock an object "@comment" in the controller_spec
> > for the function?
> > I didn't manage to do it.
>
> > def destroy
> >    @destroy_id = @comment.id #to be used in rendering partial
> >    @comment.destroy
> > end
>
> > Looks like assigns[:comment] = mock("comment") works only for views?
>
> > Thank you,
> > Evgeny
>
> > On Feb 23, 8:32 pm, David Chelimsky <dchelim... at gmail.com> wrote:
> >> On Fri, Feb 20, 2009 at 10:17 AM, Evgeny Bogdanov
>
> >> <evgeny.bogda... at gmail.com> wrote:
> >> > Hello,
>
> >> > I am trying to implement the following scenario, but I am stuck ...
> >> > The thing is I want to initialize a variable @comment when the stub
> >> > function "find_comment" is called.
> >> > The way I do it below doesn't work, since
> >> > "before_filter :find_comment" returns true/false and @comment
> >> > initialization is done inside it. Could you please give me a hint how
> >> > to do it?
>
> >> > One solution would be to use
> >> > Comment.stub!(:find).and_return(@comment) and do not use the stub
> >> > find_comment.
>
> >> That's the way to do it.
>
> >> > But how to do it in general, when there is no expression like "@var =
> >> > my_var.function" in the controller and variable @var is defined in
> >> > another place and controller just uses it.
>
> >> In general, it's best to avoid dealing directly with internal state on
> >> an object that you're specifying and only manipulate its state through
> >> public methods and/or mocks/stubs on collaborators. So in this case,
> >> I'd just stub Comment.find, as mentioned above.
>
> >> > my_var.stub!(:function).and_return(@var) doesn't seem to be working.
>
> >> > Is there is something like
> >> > my_var.stub!(:function).add_variable(@var).and_return(:true)
>
> >> Nope. For the reasons stated above. This is too invasive.
>
> >> Cheers,
> >> David
>
> >> > ?
>
> >> > Thank you,
> >> > Evgeny
> >> > =============controller_file
> >> >  before_filter :find_comment, :only => [:destroy]
>
> >> >  def destroy
> >> >    @destroy_id = @comment.id #to be used in rendering partial
> >> >    @comment.destroy
>
> >> >    respond_to do |format|
> >> >      format.js
> >> >    end
> >> >  end
>
> >> >  def find_comment
> >> >     @comment = Comment.find(:first, :conditions => ['id= ?',params
> >> > [:comment_id]])
> >> >  end
> >> > ===============spec_file
> >> > spec code
> >> > describe CommentsController, "while deleting a comment" do
> >> >  it "should render destroy.rjs in case of success" do
> >> >    @comment = mock_model(Comment)
> >> >    @comment.stub!(:id).and_return(1)
> >> >    @comment.stub!(:destroy).and_return(:true)
>
> >> >    controller.stub!(:find_comment).and_return(@comment)
>
> >> >    # execute ajax request
> >> >    request.env["HTTP_ACCEPT"] = "application/javascript"
> >> >    post :destroy, :comment_id => 1, :item_id => 1, :item_type =>
> >> > "Space"
>
> >> >    response.should render_template("destroy")
> >> >  end
> >> > end
> >> > _______________________________________________
> >> > rspec-users mailing list
> >> > rspec-us... at rubyforge.org
> >> >http://rubyforge.org/mailman/listinfo/rspec-users
>
> >> _______________________________________________
> >> rspec-users mailing list
> >> rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users
> > _______________________________________________
> > rspec-users mailing list
> > rspec-us... at rubyforge.org
> >http://rubyforge.org/mailman/listinfo/rspec-users
>
> _______________________________________________
> rspec-users mailing list
> rspec-us... at rubyforge.orghttp://rubyforge.org/mailman/listinfo/rspec-users


More information about the rspec-users mailing list