Testing "Destroying a User" fails with "count should have been changed by -1, but was changed by 0"

127 views
Skip to first unread message

netzfisch

unread,
May 19, 2013, 3:32:17 PM5/19/13
to rs...@googlegroups.com
I want to test destroying a user through the controller, therefore I do in user users_controller_spec.rb:

    it "destroys the requested user" do
      user = User.create! valid_attributes
      expect {
        delete :destroy, {:id => user.to_param}, valid_session
      }.to change(User, :count).by(-1)
    end

The valid_session is generated that way

  def valid_session
    controller.stub(current_user: mock_model(User))
  end

In other models this test setup works fine. But in the user context, I get the following error:

  1) UsersController DELETE destroy destroys the requested user
     Failure/Error: expect {
       count should have been changed by -1, but was changed by 0

I assume, this is behaviour is related to valid_session, which interacts with the test, because of creating a second user? So there is one additional user added and one destroyed, which equals to zero!

But I don't see a way to avoid this!

The destroy implementation is straight foward:

  def destroy
    @user = User.find(params[:id])

    if @user.destroy
      session[:user_id] = nil
      redirect_to root_url, notice: 'User was successfully deleted and signed out!'
  end

Any ideas, 
thanks Harm-?

David Chelimsky

unread,
May 20, 2013, 7:20:02 AM5/20/13
to rs...@googlegroups.com
On Sun, May 19, 2013 at 2:32 PM, netzfisch <tj2...@gmail.com> wrote:
I want to test destroying a user through the controller, therefore I do in user users_controller_spec.rb:

    it "destroys the requested user" do
      user = User.create! valid_attributes
      expect {
        delete :destroy, {:id => user.to_param}, valid_session
      }.to change(User, :count).by(-1)
    end

The valid_session is generated that way

  def valid_session
    controller.stub(current_user: mock_model(User))
  end
This ^^ returns an RSpec::Mocks::MethodDouble object, which is probably not what you want.
 
In other models this test setup works fine.

My guess is that is accidental - that the result of valid_session does not get used.
 
But in the user context, I get the following error:

  1) UsersController DELETE destroy destroys the requested user
     Failure/Error: expect {
       count should have been changed by -1, but was changed by 0

I assume, this is behaviour is related to valid_session, which interacts with the test, because of creating a second user?

The second user is generated with mock_model, which does not save anything to the database, so I doubt that's the underlying issue.
 
So there is one additional user added and one destroyed, which equals to zero!

But I don't see a way to avoid this!

The destroy implementation is straight foward:

  def destroy
    @user = User.find(params[:id])

    if @user.destroy
      session[:user_id] = nil
      redirect_to root_url, notice: 'User was successfully deleted and signed out!'
  end

Any ideas, 

If the idea here is that the session user is removing him/herself from the system, then the example should set up _that_ user in the session e.g.

  it "destroys the requested user" do
    user = User.create! valid_attributes
      expect {
        delete :destroy, {:id => user.to_param}, {:user_id => user.id}
      }.to change(User, :count).by(-1)
    end
  end

Since :user_id is the only key used in destroy, I _think_ this should work.

HTH,
David

netzfisch

unread,
May 21, 2013, 3:17:51 AM5/21/13
to rs...@googlegroups.com
Am Montag, 20. Mai 2013 13:20:02 UTC+2 schrieb dchel...@gmail.com:
On Sun, May 19, 2013 at 2:32 PM, netzfisch <tj2...@gmail.com> wrote:
I want to test destroying a user through the controller, therefore I do in user users_controller_spec.rb:

    it "destroys the requested user" do
      user = User.create! valid_attributes
      expect {
        delete :destroy, {:id => user.to_param}, valid_session
      }.to change(User, :count).by(-1)
    end

The valid_session is generated that way

  def valid_session
    controller.stub(current_user: mock_model(User))
  end
This ^^ returns an RSpec::Mocks::MethodDouble object, which is probably not what you want.

ok, but what would be a sensefull and descriptive way of doing this - just:

  let(:user) { User.create! valid_attributes }

  def valid_session
    { :user_id => user.id }
  end

or not to interfere the test - with the usage of a seperate user:

  let(:user) { User.create! valid_attributes }

  def valid_session
    { :user_id => FactoryGirl.create(:user) }
  end

By the way, I use the *let* statement for different test, not to create for every test a new user.


In other models this test setup works fine. 

My guess is that is accidental - that the result of valid_session does not get used.

your are right - my fault, in other models I do:

  def valid_session
    controller.stub(current_user: FactoryGirl.create(:user))
  end
It does work, furthermore now I differntiate between ordinary user, who delete their account and get sign-out and administrive users who can delete *other* users and stay logged in!

Thanks again,
Harm

David Chelimsky

unread,
May 21, 2013, 10:41:54 AM5/21/13
to rs...@googlegroups.com
That depends entirely on the intent of the example. If I understand correctly, this example specifies that the session user is removing him/herself from the system, and the outcome is that user record is deleted and that user's session is invalidated by assigning nil to the :user_id. In that case, it should be the same user, but I would probably express that right in the example to make it clear.
Reply all
Reply to author
Forward
0 new messages