R – Why do test:units and test:functionals insist on running in development environment


I'm trying to test some environment-specific settings (middleware to be specific, but it doesn't seem to matter), but I'm having trouble getting the tests to run in the correct environment. The symptoms:

  • If I run ruby test/unit/my_test.rb, all is fine because the first thing it does is require test/test_helper.rb, which sets the environment to "test" and then loads the Rails environment.
  • If I run rake test, the first batch (functionals) run fine, but the second batch (units) fail. The failure is that ENV['RAILS_ENV] somehow gets unset between batches, then config/environment.rb sees that none is set and uses the default of "development". The environment is correct at the beginning of config/environment.rb and at the beginning of the configuration block in that file, but wrong by the end. I can tell by using a puts or by deleting config/development.rb causing it to not find the file.
  • If I run rake test:units, I get the same problem as the second batch of rake test (that is, all fail)
  • If I run rake test:functionals, I get the same as for rake test:units
  • If I run rake test RAILS_ENV=test or rake test:units RAILS_ENV=test or rake test:functionals RAILS_ENV=test, all is fine!

One thing I tried that doesn't work at all is the following:

# in Rakefile:
task :set_test_env { ENV['RAILS_ENV'] = 'test' }
Rake::Task[:test].prerequisites.unshift :set_test_env
# and similarly for other test tasks

I even tried creating a separate one of those :set_test_env tasks for each test task so that I was sure it would get called before each one instead of just once. Still no dice. It does get called, and the environment is correct at the beginning of config/environment.rb but something goes wrong inside.

I have no calls to set ENV['RAILS_ENV'] in my code anywhere.

Best Solution

To give you a full answer I would have to take a look at the code, but I'll try to give you some clues that might be helpful.

First of all rake test and all the other variants (test:units, test:functionals etc.) work as follows

  1. Rake process is invoked and task test is executed in the current environment (which is development by default), that's why development.rb is always read.
  2. The Rake task invokes the test loader in a separate child process (you can verify this with ps or pstree), this is where the test_helper.rb is sourced and environment is set to test.

When you run ruby test/unit/my_test.rb the first step is skipped, so it looks like the problem lies there. Maybe you do something in development.rb that has side effects for the subprocess?