我有课:
class Vendor::Connection
VENDOR_CLIENT_ID = Rails.application.credentials.vendor_api[:client_id].freeze
VENDOR_CLIENT_SECRET = Rails.application.credentials.vendor_api[:client_secret].freeze
# ...
def token_body
{
client_id: VENDOR_CLIENT_ID,
client_secret: VENDOR_CLIENT_SECRET,
}
end
end
当我尝试使用此 Rspec Github 问题
中的任何方法模拟凭据时require 'rails_helper'
describe Vendor::Connection do
before do
allow(Rails.application.credentials).to receive(:vendor_api).and_return({ client_id: '123' })
end
it 'works' do
expect(true).to eq(true)
end
end
我收到:
Failure/Error: VENDOR_CLIENT_ID = Rails.application.credentials.vendor_api[:client_id]
NoMethodError:
undefined method `[]' for nil:NilClass
我还尝试了之前的块:
before do
stub_const('Vendor::Connection::VENDOR_CLIENT_ID', '123')
stub_const('Vendor::Connection::VENDOR_CLIENT_SECRET', '456')
stub_const('Vendor::Connection::VENDOR_PARTNER_ID', '789')
end
我仍然收到:
Failure/Error: VENDOR_CLIENT_ID = Rails.application.credentials.vendor_api[:client_id]
NoMethodError:
undefined method `[]' for nil:NilClass
我尝试过:
shared_context 'credentials' do
before do
allow(Rails.application).to receive(:credentials).and_return(OpenStruct.new(vendor_api: {client_id: '123', client_secret: '456', partner_id: '789'}))
end
end
describe Vendor::Connection do
include_context 'credentials'
it 'works' do
expect(true).to eq(true)
end
end
也返回:
Failure/Error: VENDOR_CLIENT_ID = Rails.application.credentials.vendor_api[:client_id]
NoMethodError:
undefined method `[]' for nil:NilClass
我还尝试将
binding.pry
作为 before
块中的第一行,但在到达 binding.pry
之前失败了
运行于:
ruby 3.0.5
rails 6.1.7.4
rspec 3.10.0
rspec-rails 4.1.2
任何帮助将不胜感激
确保你的常数实际上是常数。
在这种情况下,常数
VENDOR_CLIENT_ID
不是常数,因为它取决于秘密的值。
加载代码时,Ruby 到达
VENDOR_CLIENT_ID = ...
行时,它会立即尝试通过访问机密来填充值。这种情况发生在代码加载期间,在实际执行任何代码之前。
我看到有两种方法可以解决这个问题。
VENDOR_CLIENT_ID
更改为其他内容。例如缓存的类方法。def self.vendor_client_id
@_vendor_client_id ||= Rails.application.credentials.vendor_api[:client_id].freeze
end