The problem

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

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.

The solution

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

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
  Rails.env.should be_test

How does this work?

The Rails.env function looks like this:

def env
  @_env ||=["RAILS_ENV"] || ENV["RACK_ENV"] || "development")

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.