5

I have simple, new Rails 4 app which clobbers the development database when I run rake test:units, even though I've set the RAILS_ENV in test_helper.rb. I wouldn't have expected that. Here are the simple steps to reproduce it.

I have Ruby 2.0.0p247 and Rails 4.0.1.

rails new foo
rails generate scaffold gadget
rake db:migrate

I edit test/models/gadget_test.rb to look like this:

require 'test_helper'

class GadgetTest < ActiveSupport::TestCase
  test "the env" do
    assert_equal "test", Rails.env
  end
end

and I have edited the first line of test/test_helper.rb from

ENV["RAILS_ENV"] ||= "test"

to be

ENV["RAILS_ENV"] = "test"

Even so, when the tests invoke rake test:units it fails:

  1) Failure:
GadgetTest#test_the_env test/models/gadget_test.rb:5]:
Expected: "test"
  Actual: "development"

With older (Rails 3) apps I've set up, I could count on this defaulting to the test environment. What am I missing?

Fitter Man
  • 682
  • 8
  • 17
  • When i was having this issue changing `ENV["RAILS_ENV"] ||= "test"` to `ENV["RAILS_ENV"] = "test"` fixed it. Are you sure your test_helper is being loaded by `rake test:units` ? – j_mcnally Mar 02 '14 at 23:57
  • I would think `ENV["RAILS_ENV"] = "test"` is being called too late, Rails may have already cached the value of Rails.env? – j_mcnally Mar 02 '14 at 23:58
  • Does `RAILS_ENV=test rake test:units` work as expected? – j_mcnally Mar 02 '14 at 23:58
  • @j_mcnally, I am sure the test_helper is being called. To confirm, I put `raise "testhelper"` at the begging of that file. It raised the error before any tests ran. Also, running the command prefixed with `RAILS_ENV=test` definitely works right. – Fitter Man Mar 03 '14 at 20:35
  • 1
    see `http://apidock.com/rails/Rails/env/class` it seems to cache the value as @_env if there is a call to env before you set ENV["RAILS_ENV"] it may cache development as the value in a mutable way. – j_mcnally Mar 03 '14 at 20:47
  • @j_mcnally, you are getting me so close to an answer! What I've discovered is that application.rb has this line Bundler.require(:default, Rails.env) it is setting the cached value of env before it gets to my line of code. I'm not sure how to rearrange things so they play together nicely, but I'm going to try a few things. If you have any ideas, feel free to suggest. – Fitter Man Mar 04 '14 at 03:37
  • Even switching that line to Bundler.require(:default, ENV['RAILS_ENV']) doesn't seem to remedy the problem. Something else has to be invoking Rails.env, but I am unsure what it is. – Fitter Man Mar 04 '14 at 03:40

4 Answers4

6

Mystery solved, with a big tip of the hat to j_mcnally!

To force the Rails env to "test" in Rails 4 (and probably much earlier), it no longer suffices to change the first line of the test_helper.rb to

ENV["RAILS_ENV"] = "test"

This fails to reset the cached value of Rails.env, but if you invoke

Rails.env = "test"

It will reset the cached value properly. That said, there are other places where Rails.env is being invoked already, otherwise the cache wouldn't be set. One obvious one is bundler setup in application.rb, where it has Bundler.require(:default, Rails.env) and changing that to Bundler.require(:default, ENV['RAILS_ENV']) (to avoid setting the cache) still indicates that other places in the initialization must also be invoking Rails.env. The significance of all of that is that some of the setup is going to think it's running in development and then the tests will run in the "test" environment.

Net answer: I have a way to get what I want, but there may still be some danger spots lurking out there.

Fitter Man
  • 682
  • 8
  • 17
6

TL;DR ensure that require 'rails/test_unit/railtie' line is not commented out in config/application.rb


I had the same problem, was trying out Minitest as a replacement for TestUnit, and generated Rails application without it (rails new foobar --skip-test-unit), but Minitest still uses test task from rails.

And I had the following code in the config/applicaiton.rb:

# require 'rails/test_unit/railtie'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

As j_mcnally and Fitter Man pointed out, the problem is that Rails.env caches its value before ENV['RAILS_ENV'] got set, in my case it is getting called inside Rails.groups.

Trying to find in Rails sources how it sets proper test env when calling rake task, I found that it does so in the rails/test_unit/railtie.rb which got commented out.

So the solution was as simple as uncommenting require 'rails/test_unit/railtie' line.

Hope that helps.

Anton Dieterle
  • 656
  • 8
  • 8
1

The real answer: there was a stray export RAILS_ENV="development" in a shell script referenced by my profile. So this is a seat-to-keyboard interface failure, directly from Oct 31, 2013 in this thread: https://github.com/rails/rails/issues/7175

All you need to do is take that out and the problem goes away.

Fitter Man
  • 682
  • 8
  • 17
0

As far as I can tell there shouldn't be any reason to have to force the Rails.env to the test. So if you're test are running in the wrong env there is something setting the env somewhere in your code.

For me it was caused by env export I didn't realize someone had placed on the first line of an .rvmc file for the app.

Removing that export RAILS_ENV=development line from that file and restarting terminal fixed the issue.

JonathanSimmons
  • 1,528
  • 1
  • 16
  • 28