Rspec 将常量集存根到 Rails 凭证

问题描述 投票:0回答:1

我有课:

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

任何帮助将不胜感激

ruby-on-rails rspec rspec-rails rspec-mocks
1个回答
0
投票

确保你的常数实际上是常数。

在这种情况下,常数

VENDOR_CLIENT_ID
不是常数,因为它取决于秘密的值。

加载代码时,Ruby 到达

VENDOR_CLIENT_ID = ...
行时,它会立即尝试通过访问机密来填充值。这种情况发生在代码加载期间,在实际执行任何代码之前。

我看到有两种方法可以解决这个问题。

  1. 黑客的方式。更改代码加载顺序,以便仅在需要时加载此类,并且在设置 RSpec 模拟之前不会加载它。
  2. 不要对非常量值使用常量。将
    VENDOR_CLIENT_ID
    更改为其他内容。例如缓存的类方法。
def self.vendor_client_id
  @_vendor_client_id ||= Rails.application.credentials.vendor_api[:client_id].freeze
end
© www.soinside.com 2019 - 2024. All rights reserved.