How to change the environment variable of rails in testing
If you're using something like rspec, you can stub Rails.env to return a different value for the specific test example you're running:
it "should log something in production" do
Rails.stub(:env).and_return('production')
Rails.logger.should_receive(:warning).with("message")
run_your_code
end
As a simpler variation on several answers above, this is working for me:
allow(Rails).to receive(:env).and_return('production')
Or, for as I'm doing in shared_examples, pass that in a variable:
allow(Rails).to receive(:env).and_return(target_env)
I suspect this falls short of the ...StringInquirer...
solution as your app uses additional methods to inspect the environment (e.g. env.production?
, but if you code just asks for Rails.env
, this is a lot more readable. YMMV.
Sometimes returning a different environment variable can be a headache (required production environment variables, warning messages, etc).
Depending on your case, as an alternate you may be able to simply return the value you need for your test to think it's in another environment. Such as if you wanted Rails to believe it is in production for code that checks Rails.env.production?
you could do something like this:
it "does something specific when in production" do
allow(Rails.env).to receive(:production?).and_return(true)
##other assertions
end
You could do the same for other environments, such as :development?
, :staging?
, etc. If you don't need the full capacity of returning a full environment, this could be another option.
You could do
Rails.stub(env: ActiveSupport::StringInquirer.new("production"))
Then Rails.env
, Rails.development?
etc will work as expected.
With RSpec 3 or later you may want to use the new "zero monkeypatching" syntax (as mentioned by @AnkitG in another answer) to avoid deprecation warnings:
allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new("production"))
I usually define a stub_env
method in a spec helper so I don't have to put all that stuff inline in my tests.
An option to consider (as suggested in a comment here) is to instead rely on some more targeted configuration that you can set in your environment files and change in tests.
Rspec 3 onwards you can do
it "should do something specific for production" do
allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new("production"))
#other assertions
end