用户密码更新rspec

时间:2018-04-10 10:25:16

标签: ruby-on-rails testing rspec

在我的控制器中,我有一个名为update_password的方法,此方法在验证令牌后更新用户密码。但是,我的测试失败了。可能是什么问题?

在我的控制器中,

      def update_password
        user = User.find_by(email: params[:email])
        if user.nil?
          render json: { error: 'Could not update' }, status: 422
        else
          user.update(user_params)
          render json: { message: 'Successfully Updated' }, status: 200
        end
      end

     def user_params
        params.permit(:password, :password_confirmation, :current_password, :email)
      end

测试:

   describe 'update password for valid token' do
    it'should update the password' do
      user_params = {
        password: 'newpassword',
        password_confirmation: 'newpassword',
        email: user.email
      }
      put '/api/v1/update_password', params: user_params
      expect(user.password).to eq 'newpassword'
      expect(user.reload.password_confirmation).to eq 'newpassword'
      expect(user.reload.password).to eq(user.reload.password_confirmation)
      json_response = JSON.parse(response.body)
      expect(json_response['message']).to eq('Successfully Updated')
    end
   end

工厂:

FactoryBot.define do
  factory :user do
    sequence(:email) { |n| "user#{n}@example.com" }
    password 'testcase'
    username 'testcase'
    password_confirmation 'testcase'
    first_name 'testname'
    last_name 'test'
  end
end

我遇到错误:

1) UsersRequests update password for valid token should update the password
     Failure/Error: expect(user.password).to eq 'newpassword'

       expected: "newpassword"
            got: "testcase"

       (compared using ==)
     # ./spec/requests/users_requests_spec.rb:105:in `block (3 levels) in <top (required)>'

Finished in 0.35031 seconds (files took 5.69 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/requests/users_requests_spec.rb:98 # UsersRequests update password for valid token should update the password

1 个答案:

答案 0 :(得分:2)

您的控制器操作从根本上被打破。当找不到记录时(422不是401),它返回错误的响应代码,无论记录是否更新,它都返回200。您还要让用户更新电子邮件属性!

看起来应该是这样的:

def update_password
  # this will raise ActiveRecord::NotFound if the record cannot be found
  # this avoids duplication by relying on rescue_from to return 401 - not found
  user = User.find_by!(email: params[:email])
  # You need to check the return value to see if the record was updated!
  if user.update(update_password_params)
    # consider omitting the JSON payload as clients can just 
    # use the status code to determine if it was a success
    render json: { message: 'Successfully Updated' }, status: 200
  else
    render json: { error: 'Could not update' }, status: 422
  end
end

private

# this should be a subset of the params and not allow email!
def update_password_params
  params.permit(:password, :password_confirmation, :current_password)
end

您还可以使用RSpec的change matchers

在规范中做得更好
describe 'update password for valid token' do

  let!(:user) { create(:user) }
  let(:user_params) do
    {
      password: 'newpassword',
      password_confirmation: 'newpassword',
      email: user.email
    }
  end

  # don't start with 'should'
  it 'updates the password' do
    expect do
      put '/api/v1/update_password', params: user_params
      user.reload
    end.to change(user, :password).to('newpassword')
  end

  it 'is successful' do
    put '/api/v1/update_password', params: user_params
    expect(response).to have_http_status 200
  end
end

您的规范应该只测试意图行为 - 更新记录密码。

由于它是虚拟属性,因此无法测试password_confirmation - 此处不需要。您需要在单独的规范中测试密码如果不匹配则不会更新:

describe 'update password with invalid attributes' do

  let!(:user) { create(:user) }
  let(:user_params) do
    {
      password: 'newpassword',
      password_confirmation: 'newpasswordxx',
      email: user.email
    }
  end

  it 'does not update the password' do
    expect do
      put '/api/v1/update_password', params: user_params
      user.reload
    end.to_not change(user, :password)
  end

  it 'reponds with 422' do
    put '/api/v1/update_password', params: user_params
    expect(response).to have_http_status 422
  end
end