为依赖于环境变量的代码编写规范的最佳方法是什么?

时间:2012-03-08 00:28:50

标签: ruby rspec environment-variables

我正在测试一些从环境变量中提取配置的代码(由生产中的Heroku配置变量设置,我使用工头进行本地开发)。

使用RSpec测试此类代码的最佳方法是什么?

我想出了这个:

before :each do
    ENV.stub(:[]).with("AWS_ACCESS_KEY_ID").and_return("asdf")
    ENV.stub(:[]).with("AWS_SECRET_ACCESS_KEY").and_return("secret")
end

如果您不需要测试环境变量的不同值,我猜您可以在spec_helper中设置它们。

8 个答案:

答案 0 :(得分:54)

你也可以存根常量:

stub_const('ENV', {'AWS_ACCESS_KEY_ID' => 'asdf'})

或者,如果你还想要ENV的其余部分:

stub_const('ENV', ENV.to_hash.merge('AWS_ACCESS_KEY_ID' => 'asdf'))

答案 1 :(得分:22)

那会有用。

另一种方法是在代码和环境变量之间放置一层间接,就像某种易于模拟的配置对象一样。

答案 2 :(得分:6)

作为Heroku suggests,您可以使用Foreman的.env文件存储环境变量以进行开发。

如果您这样做,可以使用foreman run来运行您的规范:

foreman run bundle exec rspec spec

答案 3 :(得分:3)

如果您在测试期间使用dotenv设置环境但需要修改特定测试的env变量,则以下方法可能很有用。

比存根ENV更简单的方法是在测试期间替换环境,然后将其恢复如下:

with_environment("FOO" => "baz") do
  puts ENV.fetch("FOO")
end

使用这样的帮助(来自Homebrew source):

module Test
  module Helper
    module Env
      def with_environment(partial_env)
        old = ENV.to_hash
        ENV.update partial_env
        begin
          yield
        ensure
          ENV.replace old
        end
      end
    end
  end
end

通过使用ensure,即使测试失败,也会恢复原始环境。

setting & modifying environment variables during tests的方法进行了方便的比较,包括对ENV进行存根,在测试之前/之后替换值,以及像ClimateControl这样的宝石。

答案 4 :(得分:2)

我会避免使用ENV.stub(:[]) - 如果其他东西使用ENV(如pry),它就不起作用(你会收到关于需要存根DISABLE_PRY的错误)。

stub_const正如已经指出的那样运作良好。

答案 5 :(得分:2)

您可以使用https://github.com/littleowllabs/stub_env来实现此目的。它允许您存储单个环境变量,而不会像解决方案建议那样将所有变量存根。

安装gem然后写

before :each do
  stub_env('AWS_ACCESS_KEY_ID', 'asdf')
  stub_env('AWS_SECRET_ACCESS_KEY','secret')
end

答案 6 :(得分:1)

你想要的是dotenv gem

正如@ciastek建议的那样,在foreman下运行测试,从CLI运行规范时效果很好。但是这并没有帮助我在Sublime Text 2中使用Ruby Test运行规范.Dotenv透明地完成了你的工作。

答案 7 :(得分:1)

此语法对我有用:

module SetEnvVariable

  def set_env_var(name, value)
   # Old Syntax
   # ENV.stub(:[])
   # ENV.stub(:[]).with(name).and_return(value)

   allow(ENV).to receive(:[]) # stub a default value first if message might be received with other args as well.
   allow(ENV).to receive(:[]).with(name).and_return(value)
  end

end