[rspec-users] [RSpec] [Rails] [BDD]
julian.mann at gmail.com
Sat Feb 28 19:16:28 EST 2009
> Welcome Julian! See my comments inline below...
>> 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 ...
>> 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
>> instance_variable_set('@user', mock_model(User))
>> 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])
> 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))
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
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
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])
> Then in your action:
> def update
> @account = current_user.account
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 =
> 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:
> Or create the account stub inline with the user mock creation:
> mock_model(User, :account => mock_model(Account))
> Yes it absolutely does help! Things are really falling into place nicely
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the rspec-users