当用户使用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
1条答案
按热度按时间62lalag41#
我找到了答案。这个
prepare_user
返回nil
当我测试的时候这个
prepare_user
只需要进行以下调整(else下的另一个示例变量):