I'm writing an rspec scenario thats failing with:
(#<User:0x1056904f0>).update_attributes(#<RSpec::Mocks::ArgumentMatchers::AnyArgMatcher:0x105623648>)
expected: 1 time
received: 0 times
users_controller_spec.rb:
describe "Authenticated examples" do
before(:each) do
activate_authlogic
@user = Factory.create(:valid_user)
UserSession.create(@user)
end
describe "PUT update" do
it "updates the requested user" do
User.stub!(:current_user).and_return(@user)
@user.should_receive(:update_attributes).with(anything()).and_return(true)
put :update, :id => @u开发者_Go百科ser , :current_user => {'email' => 'Trippy'}
puts "Spec Object Id : " + "#{@user.object_id}"
end
users_controller.rb:
def update
@user = current_user
puts "Controller Object ID is : " + "#{@user.object_id}"
respond_to do |format|
if @user.update_attributes(params[:user])
format.html { redirect_to(root_url, :notice => 'Successfully updated profile.') }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
end
end
end
user.rb - factories
Factory.define :valid_user, :class => User do |u|
u.username "Trippy"
u.password "password"
u.password_confirmation "password"
u.email "elephant@gmail.com"
u.single_access_token "k3cFzLIQnZ4MHRmJvJzg"
u.id "37"
end
Authlogic's standard helper methods like current_user
don't call User.find
directly. I believe it does current_user_session.user
, where current_user_session
calls UserSession.find
, so you're not calling User.find
directly. You could do some fancy chain stubbing there, but my suggestion is just to add this to your controller spec instead of what you're currently stubbing:
stub!(:current_user).and_return(@user)
In RSpec2 you might have to do
controller.stub!(:current_user).and_return(@user)
Edit: This should be your whole spec file:
describe "Authenticated examples" do
before(:each) do
activate_authlogic
@user = Factory.create(:valid_user)
UserSession.create(@user)
end
describe "PUT update" do
describe "with valid params" do
it "updates the requested user" do
stub!(:current_user).and_return(@user)
@user.should_receive(:update_attributes).with(anything()).and_return(true)
put :update, :id => @user , :current_user => {'email' => 'Trippy'}
end
end
I think you're confusing stubs with message expectations. The line
User.should_receive(:find)
tells Rspec to expect the User model to receive a find message. Whereas:
User.stub!(:find)
replaces the find method so that the test can pass. In your example the thing you're testing is whether update_attributes
is called successfully, so that ought to be where the message expectation goes, and the job of all the other testing code is just to set up the prerequisites.
Try replacing that line with:
User.stub!(:find).and_return(@user)
Note that find
returns the object, not just its id. Also, note that stubbing out find
here serves only to speed things up. As written the example gets through should_receive(:find)
successfully, and that is happening because you're using Factories to create users in the test database. You could take the stub out and the test should still work, but at the cost of hitting the database.
Another tip: if you're trying to figure out why a controller test isn't working, sometimes it's helpful to know if it is being blocked by before
filters. You can check for this with:
controller.should_receive(:update)
If that fails, the update
action is not being reached, probably because a before
filter has redirected the request.
精彩评论