在轨道ENV上的红宝石中存储键/值对

时间:2016-05-09 07:23:16

标签: ruby-on-rails rspec

我想测试一下ENV键值对我的代码的影响。我正在使用

来解决这个问题
allow(ENV).to receive(:[]).with('ADWORDS_RUN').and_return('No')

这一直有效,直到我更改了目标代码以包含访问另一个ENV密钥。目标代码现在包括以下

 def not_local_machine?
    !ENV['LOCAL_MACHINE']
 end

现在测试在上述函数中失败并显示错误消息

 Failure/Error: get 'home'
   ENV received :[] with unexpected arguments
     expected: ("ADWORDS_RUN")
          got: ("LOCAL_MACHINE")
    Please stub a default value first if message might be received with other args as well.

看来我目前的存根方法是擦除其他ENV键。如何存根ENV键以避免此问题?

4 个答案:

答案 0 :(得分:6)

您可以使用

stub_const 'ENV', ENV.to_h.merge('ADWORDS_RUN' => 'No')

答案 1 :(得分:0)

您正在覆盖/覆盖ENV的[]方法。原来的意思完全消失了。

查看https://github.com/rspec/rspec-mocks并查找“任意处理”一章。它包含以下示例代码:

expect(double).to receive(:msg) do |arg|
  expect(arg.size).to eq 7
end

你应该能够根据自己的需要采用这种方法......(未经测试的)

dummy_env = { ADWORDS_RUN: 1, LOCAL_MACHINE: 2 }
allow(ENV).to receive(:[]) do |key|
  dummy_env[key] or raise "#{key} not expected"
end

或者如果你想保留所有旧的ENV条目

env_clone = ENV.clone
allow... do|key|
   dummy_env[key] or env_clone[key]
end

答案 2 :(得分:0)

这是我解决该问题的方法:

before { allow(ENV).to receive(:[]).and_call_original }

context 'ADWORDS_RUN is No' do
  before { allow(ENV).to receive(:[]).with('ADWORDS_RUN').and_return('No') }

  [example block]
end

(此外,我建议使用“ false”之类的东西代替“否”。)

答案 3 :(得分:0)

对于modifying ENV's in tests,Thoughtbot的climate_control宝石值得一看。

您将测试包装在ClimateControl块周围,以控制对ENV值的临时更改。以您的示例为例:

ClimateControl.modify ADWORDS_RUN: 'No' do
  expect(AdwordsTask.new.run?).to eq(false)
end

要与RSpec一起使用,可以在您的规范中定义它:

def with_modified_env(options, &block)
  ClimateControl.modify(options, &block)
end

这将提供更直接的方法来修改/存根环境值:

require 'spec_helper'

describe AdwordsTask, 'name' do
  it 'does not run adwords' do
    with_modified_env ADWORDS_RUN: 'No' do
      expect(AdwordsTask.new.run?).to eq(false)
    end
  end

  def with_modified_env(options, &block)
    ClimateControl.modify(options, &block)
  end
end
相关问题