在我的控制器中,我有一个名为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
答案 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