What is the best way to write specs for code that depends on environment variables?

RubyRspecEnvironment Variables

Ruby Problem Overview


I am testing some code that pulls its configuration from environment variables (set by Heroku config vars in production, for local development I use foreman).

What's the best way to test this kind of code with RSpec?

I came up with this:

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

If you don't need to test different values of the environment variables, I guess you could set them in spec_helper instead.

Ruby Solutions


Solution 1 - Ruby

You also can stub the constant:

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

Or, if you still want the rest of the ENV:

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

Solution 2 - Ruby

That would work.

Another way would be to put a layer of indirection between your code and the environment variables, like some sort of configuration object that's easy to mock.

Solution 3 - Ruby

This syntax works for me:

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

Solution 4 - Ruby

As Heroku suggests, you can use Foreman's .env file to store environment variables for development.

If you do that, you can use foreman run to run your specs:

foreman run bundle exec rspec spec

Solution 5 - Ruby

If you're using dotenv to setup your environment during tests but need to modify an env variable for a specific test then following approach can be useful.

A simpler method than stubbing ENV is to replace the environment for the duration of the test, and then restore it afterwards like so:

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

Using a helper like this:

module EnvironmentHelper
  def with_environment(replacement_env)
    original_env = ENV.to_hash
    ENV.update(replacement_env)

    yield
  ensure
    ENV.replace(original_env)
  end
end

By using ensure the original environment is restored even if the test fails.

There's a handy comparison of methods for setting & modifying environment variables during tests including stubbing the ENV, replacing values before / after the test, and gems like ClimateControl.

Solution 6 - Ruby

I'd avoid ENV.stub(:[]) - it does not work if other things are using ENV such as pry(you'll get an error about needing to stub DISABLE_PRY).

#stub_const works well as already pointed out.

Solution 7 - Ruby

You can use https://github.com/littleowllabs/stub_env to achieve this. It allows you to stub individual environment variables without stubbing all of them as your solution suggested.

Install the gem then write

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

Solution 8 - Ruby

What you want is the dotenv gem.

Running tests under foreman, as @ciastek suggests, works great when running specs from CLI. But that doesn't help me run specs with Ruby Test in Sublime Text 2. Dotenv does exactly what you, transparently.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLuke FranclView Question on Stackoverflow
Solution 1 - RubyiGELView Answer on Stackoverflow
Solution 2 - RubynicholaidesView Answer on Stackoverflow
Solution 3 - Rubyaldrien.hView Answer on Stackoverflow
Solution 4 - RubyciastekView Answer on Stackoverflow
Solution 5 - RubyodlpView Answer on Stackoverflow
Solution 6 - RubyCalvinView Answer on Stackoverflow
Solution 7 - RubyLiam BennettView Answer on Stackoverflow
Solution 8 - RubyTim ScottView Answer on Stackoverflow