如何编写确认密码重置令牌已保存到数据库的RSpec测试?

时间:2017-02-10 02:43:02

标签: ruby-on-rails ruby rspec ruby-on-rails-5

我正在为我的Rails 5 API编写测试,以确认每当用户请求重置密码时都会生成password_reset_token。

我有一个简短的password_reset_controller来处理初始请求:

class PasswordResetController < ApplicationController
  def new
    @user = User.find_by(email: params[:email].to_s.downcase)
    @user.send_password_reset if @user
  end
end

send_password_reset是我的用户模型中的一个方法,它调用generate_password_reset_instructions:

def send_password_reset
  self.generate_password_reset_instructions
  UserMailer.password_reset(self).deliver
end

def generate_password_reset_instructions
    self.password_reset_token = SecureRandom.hex(10)
    self.password_reset_sent_at = Time.now.utc
    save
end

这应该将password_reset_token保存到我的db(事实上,当我调试它时,我知道它通过这些代码行)。以下测试套件通过,但最后一个测试套件除外:

require 'rails_helper'

RSpec.describe 'Password Reset API' do
    let!(:user) { create(:user) }
  describe 'POST password_reset/new' do

    it 'returns status code 204 with user found' do
      post '/password_reset/new', params: {email: user.email}
      expect(response).to have_http_status(204)
    end

    it 'returns status code 204 with no user found' do
      post '/password_reset/new', params: {email: 'not#anemail.com'}
      expect(response).to have_http_status(204)
    end

    it "sends an email" do
      expect { UserMailer.password_reset(user).deliver }.to change { ActionMailer::Base.deliveries.count }.by(1)
    end

    it 'confirmation_email is sent to the right user' do
      UserMailer.password_reset(user).deliver
      mail = ActionMailer::Base.deliveries.last
      expect(mail.to[0]).to eq user.email
    end

    it 'generates password_reset_token' do
      expect { post '/password_reset/new', params: {email: user.email} }.to change { user.password_reset_token }
    end
  end
end

我在终端获得的结果是:

Failures:

  1) Password Reset API POST password_reset/new generates password_reset_token
     Failure/Error: expect { post '/password_reset/new', params: {email: user.email} }.to change { user.password_reset_token }
       expected result to have changed, but is still nil
     # ./spec/requests/password_reset_spec.rb:28:in `block (3 levels) in <top (required)>'
     # ./spec/rails_helper.rb:56:in `block (3 levels) in <top (required)>'
     # ./spec/rails_helper.rb:55:in `block (2 levels) in <top (required)>'

这似乎可能是由于没有保存到测试数据库的值,但是在其他帖子中提出建议(如移动ENV['RAILS_ENV'] ||= 'test')到rails_helper.rb的顶部并不能解决问题。我知道实际的方法是有效的,因为我能够通过运行服务器和发出请求来手动获得所需的结果,我只是不能编写测试来确认它确实有效。正如我的测试中的语法所表明的那样,我在测试中使用FactoryGirl来生成用户。

关于为什么最后一次测试(it 'generates password_reset_token' do)未通过的任何想法?

1 个答案:

答案 0 :(得分:3)

RSpec.describe 'Password Reset API' do
  let!(:user) { create(:user) }
  ....

  it 'generates password_reset_token' do
    expect { post '/password_reset/new', params: {email: user.email} }.to change { user.password_reset_token }
  end
end

您的期望:

  • 您正在创建用户并期望对其进行更改。

发生了什么:

  • 您在测试中创建了一个Ruby用户对象
  • 您希望更改该对象
  • 您的Rails代码初始化一个新的User对象,用于更新数据库并更改属性
  • 您的测试对象保持不变

您需要做的是reload使用user.reload.password_reset_token

从数据库中使用新的属性值fruits = ['apple', 'orange', 'blueberry', strawberry']您的测试对象