I had some conditional logic I needed to test that was based on the current Rails environment. Basically something like:
if Rails.env.production? # Do something elsif Rails.env.staging? # Do something else end
I needed to stub out the
Rails.env call. I had a quick Google around but I couldn’t really find a way of doing this I was happy with.
I whipped up this function that allows you to set the Rails environment to whatever you want:
def stub_env(new_env, &block) original_env = Rails.env Rails.instance_variable_set("@_env", ActiveSupport::StringInquirer.new(new_env)) block.call ensure Rails.instance_variable_set("@_env", ActiveSupport::StringInquirer.new(original_env)) end
Put the above function in your spec file or your spec_helper.rb. The function can be called as such:
it "passes" do stub_env "development" do Rails.env.should be_development end Rails.env.should be_test end
How does this work?
Rails.env function looks like this:
def env @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development") end
So all you’re doing is setting the cached instance variable to the environment you want.
Follow Up (June 20, 2011)
So two distinct issue have come up as a result of the above content.
Firstly, there was no ensure meaning that if an exception was raised in the middle of the stub then the environment would be changed for the remaining tests. This was a stupid mistake but, it happens, so I’ve updated the gist and my code.
Secondly, the issue of checking environment in code. The solution for this would be to have a constant in each env file that defines whatever it is you are using the env check for. So in the example I was working with each env file would have a EMAIL_TARGET constant.
You still need to test this, so the stub provided is still useful in this regard.