[rspec-users] [RSpec] [Rails] [BDD]

julian mann julian.mann at gmail.com
Sat Feb 28 19:16:28 EST 2009


> Welcome Julian!  See my comments inline below...


Thanks Ben!

>
>
>> I am trying to spec a fairly simple controller update action for an
>> account. The account belongs_to :user and user has_one :account.
>>
>>
>> here's the action
>>
>>  def update
>>    @account = @user.account
>>    respond_to do ...
>>  end
>>
>> I'm trying to avoid fixtures, and I'm using rspec's own mock framework
>>
>> In normal operation the @user instance variable is assigned in a
>> before_filter (get_user) - so
>>
>> i figured if I stub that I could then assign user:
>>
>> before(:each) do
>> controller.stub!(:get_user).and_return(true)
>> instance_variable_set('@user', mock_model(User))
>> end
>>
>> I tried other variations on this - like instance_variable_set('@user',
>> User.new)  and others
>>
>> but @user is never assigned
>>
>
> When you use instance_variable_set you are setting the variable inside the
> example group (the test) and not the actual controller it self.


Ah ok - got it now.  Thanks for clearing that up !
Although it does leave me slightly confused as to what the object is that
performs the test - i.e. who that instance variable belongs to (not that I
need it now). I mean - unlike Test::Unit, there is no 'class AccountTest ' -
I'll dig around and find out.

In order to use your mock user in your controller you need to stub whatever
> your get_user method uses to find the user.  You do not want to stub out the
> get_user method otherwise your controller will never be able to set the user
> object. For example, say you have this:
>
> def get_user
>  @user = User.find(session[:user])
> end
>
> In order to stub this correctly you would not stub get_user but instead
> stub the find call on User, like so:
>
> before(:each) do
>  User.stub!(:find).and_return( @user = mock_model(User))
> end
>

Excellent - I will do this - makes sense now ;)


>
> Doing this will stub the user in the controller and also allow you to
> access the same object (as @user) in your example group. ( The fact that I
> named it @user in the example has nothing to do with it- that is just to be
> consistent.)
>

I see.. so returning ( @user = mock_model(User) ) means the example_group
can access the user as @user. but returning only ( mock_model(User)) would
mean @user is still set up in the controller, but not available the example
group.

On another note, what many rails apps do is instead of using filters to set
> instance variables you can extract it into an accessor method that caches
> it.  For example, instead of having the get_user method as a filter you
> could simply have this:
>
> def current_user
>  @current_user ||= User.find(session[:user])
> end


>
> Then in your action:
>
> def update
>   @account = current_user.account
>   ....
> end


Cool -I'll do this! its a minor adjustment to what I have at the moment.

>
>
> To stub this you could do what I listed above or stub out the current_user
> method like so:
>
> before(:each) do
>  controller.stub!(:current_user).and_return( @current_user =
> mock_model(User))
> end
>
>
> In general you should not stub or mock methods on the object you are trying
> to test.

That said, stubbing current_user on the controller is something that is done
> often and is usually a low-risk thing to do.  (I just thought I would point
> out the bad smell.)


Yes I could smell it too --  It seems obvious, in hindsight, that if you
stub out methods on the object you are testing, then you are not really
testing it. So thanks for bringing that up.

>
> Now, to stub out the account on user, in your examples you would just need
> to say something like:
>
> @current_user.stub!(:account).and_return(mock_model(Account))
>
> Or create the account stub inline with the user mock creation:
>
> mock_model(User, :account => mock_model(Account))
>
> HTH,
>
> Yes it absolutely does help!  Things are really falling into place nicely
now. Thankyou!


Julian
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://rubyforge.org/pipermail/rspec-users/attachments/20090228/ad2011ca/attachment.html>


More information about the rspec-users mailing list