nomethoderror:rspec中nil:nilclass的未定义方法“access\u token”

7bsow1i6  于 2021-09-29  发布在  Java
关注(0)|答案(1)|浏览(358)

当用户使用octokit gem向github/google服务发送验证码以接收有效令牌时,我正在尝试通过用户身份验证测试。我正在rspec中为nil:nilclass运行nomethoderror未定义的方法“access\u token”。
这是我的终端的屏幕截图:
问题的rspeca终端截图中nil:nilclass的未定义方法“access\u token”
这是我的userauthenticator库:

class UserAuthenticator
  class AuthenticationError < StandardError; end

  attr_reader :user, :access_token

  def initialize(code)
    @code = code
  end

  def perform
    raise AuthenticationError if code.blank?
    raise AuthenticationError if token.try(:error).present?

    prepare_user
    @access_token = if user.access_token.present?
      user.access_token
     else
      user.create_access_token
    end
  end

  # ----------------------------------------------------------------------------
  private

  def client
    @client ||= Octokit::Client.new(
      client_id: ENV['GITHUB_CLIENT_ID'],
      client_secret: ENV['GITHUB_CLIENT_SECRET']
    )
  end

  def token
    @token ||= client.exchange_code_for_token(code)
  end

  def user_data
    @user_data ||= Octokit::Client.new(
      access_token: token
    ).user.to_h.slice(:login, :url, :avatar_url, :name)
  end

  def prepare_user
    if User.exists?(login: user_data[:login])
      @user = User.find_by(login: user_data[:login])
    else
      User.create(user_data.merge(provider: 'github'))
    end
  end

  attr_reader :code
end

这是用于用户身份验证的我的rspec文件:

require 'rails_helper'

RSpec.describe UserAuthenticator do
  describe '#perform' do
    let(:authenticator) { described_class.new('sample code') }

    subject { authenticator.perform }

    context 'then the code is invalid' do
      let(:error) {
        double("Sawyer::Resource", error:'bad_verification_code')
      }
      before do
        allow_any_instance_of(Octokit::Client).to receive(
          :exchange_code_for_token).and_return(error)
      end
      it "should raise an error" do
        expect{subject}.to raise_error(UserAuthenticator::AuthenticationError)
        expect(authenticator.user).to be_nil
      end
    end

    context 'when code is correct' do
      let(:user_data) do
        {
          login: 'nklobuc1',
          url: 'http://example.com',
          avatar_url: 'http://example.com/avatar',
          name: 'Nikola'
        }
      end

      before do
        allow_any_instance_of(Octokit::Client).to receive(
          :exchange_code_for_token).and_return('validaccestoken')

          allow_any_instance_of(Octokit::Client).to receive(
            :user).and_return(user_data)
      end

      it "should save the user when does not exist" do
        expect{subject}.to change{ User.count }.by(1)
        expect(User.last.name).to eq('Nikola')
      end

      it "should reuse already registered user" do
        user = create :user, user_data
        expect{subject}.not_to change{User.count}
        expect(authenticator.user).to eq(user)
      end

      it "should create and set user's access token" do
        pp subject
        expect{subject}.to change{AccessToken.count}.by(1)
        expect(authenticator.access_token).to be_present
      end
    end
  end
end

这是用户模型:

class User < ApplicationRecord
  validates :login, presence: true, uniqueness: true
  validates :provider, presence: true

  has_one :access_token, dependent: :destroy
end

最后,这是accesstoken模型:

class AccessToken < ApplicationRecord
  belongs_to :user, class_name: "User", :foreign_key => :user_id
  validates_uniqueness_of :user_id
  after_initialize :generate_token

  private

  def generate_token
    loop do
      break if token.present? && !AccessToken.exists?(token: token)
      self.token = SecureRandom.hex(10)
    end

  end
end
62lalag4

62lalag41#

我找到了答案。这个 prepare_user 返回 nil 当我测试的时候

it "should save the user when does not exist" do
        expect{subject}.to change{ User.count }.by(1)
        expect(User.last.name).to eq('Nikola')
      end

这个 prepare_user 只需要进行以下调整(else下的另一个示例变量):

def prepare_user
    if User.exists?(login: user_data[:login])
      @user = User.find_by(login: user_data[:login])
    else
      @user = User.create(user_data.merge(provider: 'github'))
    end
  end

相关问题