首页 > 解决方案 > 使用 RSpec 测试受 Rails 中“config”下定义的常量影响的行为

问题描述

config/environment.rb我有一个 Rails 应用程序,它在:中定义了以下常量RABBIT_ENABLED = ENV.key? ("RABBIT_PORT"),它是一个布尔值。同时在另一个文件中config/initializers/rabbit.rb,我有一些看起来像这样的代码:

if RABBIT_ENABLED
  options.merge(load_rabbit_env!)
else
  # do something else
end

load_rabbit_env!方法尝试使用读取其他环境变量ENV.fetch,因此容易引发异常。这正是我想要测试的。

我希望能够编写一个测试,在其中我可以根据RABBIT_ENABLED是真还是假来断言我的 RabbitMQ 启动的行为(例如,如果常量为真但缺少其他环境变量,则会引发异常)。但是,该常量似乎无法存根,可能是因为常量是由 RSpec 运行时定义的,它已经加载了 Rails 应用程序并且不会重新读取它的值以进行测试?

我想知道在这种情况下人们会建议我做什么。理想情况下,我不想更改常量的定义位置,但我知道这里可能有必要。

标签: ruby-on-railsruby

解决方案


RSpec 支持存根常量

所以你可以通过存根RABBIT_ENABLEDtrue 或 false创建 2 个上下文

describe "your test" do
  context "RABBIT ENABLED"
   before(:each) do
     stub_const("RABBIT_ENABLED", true)
   end
   # ...
  end

  context "RABBIT DISABLE" do
   before(:each) do
    stub_const("RABBIT_ENABLED", false)
   end
   # ...
  end 
end

更新

如果您想测试initializer,您可以隔离配置的逻辑,然后您可以将该逻辑作为普通的 ruby​​ 对象进行测试,您可以在其中存根常量:

# config/testable/rabbit_config.rb
class RabbitConfig
  def apply(config, *args)
   # testable logic
   if RABBIT_ENABLED
     options.merge(load_rabbit_env!)
   else
     # do something else
   end
  end
end

创建一个第一个初始化程序0_load_testable_config_object.rb,它将在加载testable configs其他初始化程序之前加载所有初始化程序(或者您可以手动要求)

# config/initializers/0_load_testable_config_object.rb
Dir[File.join(Rails.root, "config", "testable", "**/*.rb")].each {|l| require l }

# config/initializers/rabbit.rb
Rabbit.setup do |config|
 RabbitConfig.new.apply(config)
 # ...
end

现在你可以像上面一样RabbitConfig通过 stub_const进行测试。RABBIT_ENABLED


推荐阅读