June 22, 2015

How to stub Rails environment in tests

Problem

You want to execute some code only in the production environment. So you add the following condition into your code:

if Rails.env.production?
  # do awesome stuff
end

It is simple and it works. But how are you going to test that code?

You can stub Rails.env.production? to return true and it will work. But the test will be brittle and it will fail when you (or someone else) change your condition. For example into something like this:

if ['staging', 'production'].include?(Rails.env)
  # do awesome stuff
end

You did not stub Rails.env so it will return test.

Solution

The solution is to use StringInquirer:

irb(main):001:0> env = ActiveSupport::StringInquirer.new('production')
=> "production"
irb(main):002:0> env.production?
=> true
irb(main):003:0> env.test?
=> false
irb(main):004:0> env
=> "production"
# MiniTest version
def test_my_code
  Rails.stub(:env, ActiveSupport::StringInquirer.new('production')) do
    # test code    
  end
end
# RSpec version
it 'tests my code' do
  allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production'))
  # test code
end

Hey there!

My name is Patrik Bóna and I am the only programmer at Memberful. This blog is kind of dead, but I just started my own Ruby on Rails screencast. Follow me on Twitter if you want to be notified about my newest videos.