Reputation: 16383
I want to test the effect of the value of an ENV key on my code. I am stubbing this by using
allow(ENV).to receive(:[]).with('ADWORDS_RUN').and_return('No')
This was working until I changed the target code to include accessing another ENV key. The target code now includes the following
def not_local_machine?
!ENV['LOCAL_MACHINE']
end
The test now fails in the above function with the error message
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.
It appears that my current method of stubbing is wiping out other ENV keys. How do I stub an ENV key to avoid this problem?
Upvotes: 5
Views: 4028
Reputation: 2947
For modifying ENV's in tests, Thoughtbot's climate_control gem is worth a look.
You wrap your test around ClimateControl
block to control temporary changes to ENV values. Using your example:
ClimateControl.modify ADWORDS_RUN: 'No' do
expect(AdwordsTask.new.run?).to eq(false)
end
To use with RSpec, you could define this in your spec:
def with_modified_env(options, &block)
ClimateControl.modify(options, &block)
end
This would allow for more straightforward way to modify/stub environment values:
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
Upvotes: 0
Reputation: 2336
This is how I solved that issue:
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
(Aside, I recommend using something like 'false' instead of 'No'.)
Upvotes: 3
Reputation: 8345
You are overriding/overwriting the []
method of ENV. The original meaning is gone completely.
Check out https://github.com/rspec/rspec-mocks and look for the chapter "Arbitrary Handling". It contains this sample code:
expect(double).to receive(:msg) do |arg|
expect(arg.size).to eq 7
end
You should be able to adopt that for your needs... something along the lines of (untested)
dummy_env = { ADWORDS_RUN: 1, LOCAL_MACHINE: 2 }
allow(ENV).to receive(:[]) do |key|
dummy_env[key] or raise "#{key} not expected"
end
Or if you want to keep all old ENV entries
env_clone = ENV.clone
allow... do|key|
dummy_env[key] or env_clone[key]
end
Upvotes: -1