12

I am using Rails 4.2 with Ruby 2.2 and rspec for testcases. I have set

Rails.env = 'test'

in both my spec_helper and rails_helper. Here is my database.yml file:

development:
  adapter: postgresql
  encoding: unicode
  database: app_dev
  pool: 5
  username: postgres
  password: root

test:
  adapter: postgresql
  encoding: unicode
  database: app_test
  pool: 5
  username: postgres
  password: root

production:
  adapter: postgresql
  encoding: unicode
  database: app_prod
  pool: 5
  username: postgres
  password: root

Here is my rails_helper:

Rails.env = 'test'
require 'spec_helper'
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

ActiveRecord::Migration.maintain_test_schema!

RSpec.configure do |config|
  config.include JsonHelper
  config.include PathHelper
  config.include S3Helper
  config.fixture_path = "#{::Rails.root}/spec/fixtures"
  config.use_transactional_fixtures = true
  config.infer_spec_type_from_file_location!
end

application.rb:

require File.expand_path('../boot', __FILE__)

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

module AppName
  class Application < Rails::Application
    config.generators do |g|
      g.assets = false
      g.helper = false
      g.views = false
    end

    # Load all locale files
    config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
    config.i18n.load_path += Dir[Rails.root.join(
                              'config', 'locales', '**', '**', '*.{rb,yml}')]
    config.autoload_paths += %W(#{config.root}/lib)
    config.autoload_paths += Dir["#{config.root}/lib/**/"]
    config.autoload_paths += Dir["#{config.root}/app/workers/"]
    config.action_controller.include_all_helpers = false
    config.active_record.schema_format           = :sql
    config.i18n.available_locales = [:en, :hi, :mr]
    config.i18n.default_locale = :hi
    config.i18n.fallbacks = [:en]
    config.active_record.raise_in_transactional_callbacks = true
  end
end

Gemfile:

source 'https://rubygems.org'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.2.0'

# Use postgresql as the database for Active Record
gem 'pg', '~> 0.18.2'

# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'

# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'

# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.1.0'
# Turbolinks makes following links in your web application faster
gem 'turbolinks', '~> 2.5.3'

# Use Unicorn as the app server
gem 'unicorn', '~> 4.9.0'

# Use jquery as the JavaScript library
gem 'jquery-rails', '~> 4.0.4'

# Integrate the jQuery Validation plugin into the Rails asset pipeline
gem 'jquery-validation-rails', '~> 1.13.1'

# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.0'

# bundle exec rake doc:rails generates the API under doc/api.
gem 'sdoc', '~> 0.4.0', group: :doc

# use swagger for api documentation
gem 'swagger-docs', '~> 0.1.9'

# for consuming restful web services
gem 'httparty', '~> 0.13.5'

# for ActiveRecord model/data translations
gem 'globalize', '~> 5.0.0'

# generates accessors for translated fields
gem 'globalize-accessors', '~>0.2.1'

# Amazon Web service SDK Ruby
gem 'aws-sdk', '~> 2.1.0'

# cloud services for S3
gem 'fog', '~> 1.33.0'

# handle file uploads
gem 'carrierwave', '~>0.10.0'

# Photo Resizing
gem 'mini_magick', '~> 4.2.7'

# Background Jobs
gem 'sidekiq', '~> 3.4.2'

# Geocoder
gem 'geocoder', '~> 1.2.9'

# active admin
gem 'activeadmin', '~> 1.0.0.pre1'

# for authentication
gem 'devise', '~> 3.5.1'

# for roles of active admin
gem 'rolify', '~> 4.0.0'

# for authorization
gem 'cancan', '~> 1.6.10'

group :development, :test do
  # Debugging using pry
  gem 'pry-rails', '~> 0.3.4'
  gem 'pry-byebug', '~> 3.1.0'

  # testing framework for rails
  gem 'rspec-rails', '~> 3.1.0'
  gem 'rspec-collection_matchers', '~> 1.1.2'
  gem 'factory_girl_rails', '~> 4.4.1'
  gem 'shoulda-matchers', '~> 2.8.0'

  # code test coverage
  gem 'simplecov', '~> 0.7.1'
  gem 'simplecov-rcov', '~> 0.2.3'
  # Access an IRB console on exception pages or by using <%= console %> in views
  gem 'web-console', '~> 2.0'

  # speeds up development by keeping your application running in the background
  gem 'spring', '~> 1.3.6'
end

group :development do
  # generates ER diagrams for rails application
  gem 'rails-erd', '~> 1.4.1'
end

group :test do
  # set of strategies for cleaning your database
  gem 'database_cleaner', '~> 1.3.0'
end

When I run my test cases, Rails.env is 'test' as expected (used pry to verify). However my test cases are always hitting the development database.

Rails.env
#=> "test"

ActiveRecord::Base.connection_config
#=> {:adapter=>"postgresql", :encoding=>"unicode", :database=>"app_dev", :pool=>5, :username=>"postgres", :password=>"root"}

spec_helper:

require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
require 'simplecov'
require 'simplecov-rcov'
require 'database_cleaner'
require 'factory_girl_rails'

ENV['RAILS_ENV'] ||= 'test'
SimpleCov.start

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
  # Database Cleaner
  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
    Rails.application.load_seed
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

  config.expect_with :rspec do |expectations|
    expectations.include_chain_clauses_in_custom_matcher_descriptions = true
  end

  config.mock_with :rspec do |mocks|
    mocks.verify_partial_doubles = true
  end
end

SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter

I have been scratching my head since last few hours but nothing seems to solve the mystery. Any help would be greatful!

Aaditi Jain
  • 6,969
  • 2
  • 24
  • 26
  • Is it actually saving information to your dev db? Have you tried restarting your server? – Wes Foster Sep 11 '15 at 13:16
  • @WesFoster : Yes. I did restart my server too. I have a users table with unique constraint on mobile_number. When I saw my test case failing, I used Pry and did a `User.all`. It showed up all my users in my dev database. Same for other tables also. – Aaditi Jain Sep 11 '15 at 13:19
  • And how do you verify that your test hits development db? – dimakura Sep 11 '15 at 14:00
  • 1
    Can you debug this `ActiveRecord::Base.connection_config` ? – dimakura Sep 11 '15 at 14:02
  • @dimakura: I am updating my question with these details. Thanks :) – Aaditi Jain Sep 14 '15 at 07:41
  • What happens if you remove your dev database from your database.yml file and restart? – Yule Sep 14 '15 at 09:59
  • @Yule : Error on running rspec `'development' database is not configured. Available: ["test", "production"] (ActiveRecord::AdapterNotSpecified)` – Aaditi Jain Sep 14 '15 at 10:01
  • If you add ActiveRecord::Base.establish_connection to your rails_helper does that help? – Yule Sep 14 '15 at 10:07
  • @Yule: Something that finally works. It correclty sets my db to app_test when running rspec! Thanks a lot. Can you also explain me why do I have to explicitly `establish_connection` to make my rspec work correctly? – Aaditi Jain Sep 14 '15 at 10:17
  • Since Rails 7 use `ActiveRecord::Base.connection_db_config` instead of `ActiveRecord::Base.connection_config` (this one is deprecated) – Nick Roz Jun 01 '22 at 14:50

7 Answers7

12

The reason your tests hit the development database is because you have defined ENV['DATABASE_URL'] somewhere in your environment.

There are two ways of specifying the database connection to be used:

  1. Specifying the ENV['DATABASE_URL']
  2. Using the very popular database.yml file

In many cases the first one takes prescedence over the latter.

I realized I had a problem similar to yous after using ENV['DATABASE_URL'] to set my production database, only to find out that all my environments (test & development) suddenly had started to use my production database regardless of content in database.yml.

To solve my problem all I did was change the name on the environment variable to something else, so that it no longer overwrite my database.yml configurations.

Reading this will solve your problem: Connection Preference information

Community
  • 1
  • 1
JBlanco
  • 517
  • 5
  • 9
8

It sounds as though somewhere in your environment (maybe one of your gems) it is setting your environment to dev or establishing a connection to your dev database.

To explicitly make it connect to the test database, add:

ActiveRecord::Base.establish_connection

to your rails_helper.

Prime candidate for troublemaker would be `gem 'rails-erd', '~> 1.4.1'. If you have this as auto-generating the diagram on migrate, when the test schema is migrated, it will connect to the dev database to dump a diagram.

Try removing this gem or perhaps the '.rake' file and see what happens.

Yule
  • 9,668
  • 3
  • 51
  • 72
  • Thanks You :) Your answer did help me correctly set the database to test database. However I am still a little doubtful for the reasoning behind your answer. I will wait for some time more for a clearer answer else will mark your answer as accepted. Thanks a lot for looking into it. Please let me know if you require more details/file to debug on the odd behaviour of rails_helper – Aaditi Jain Sep 14 '15 at 10:33
  • I'm glad I can help, and given I solved the issue - an upvote wouldn't go astray ;). Unfortunately it's impossible to say why this is needed as the code in your question does not give a reproducible instance. i.e. if i start a new rails project with nothing but your rails_helper, rspec and one test - I do not get the same issue. So the problem is elsewhere. Likely application.rb or one of your gems. Can you show these? – Yule Sep 14 '15 at 12:38
  • agreed and upvoted :). Also updated my question with application.rb and gemfile. – Aaditi Jain Sep 15 '15 at 11:13
  • It is not the rails-erd gem which is causing the problem. I removed the gem and tested and got the same problem. I am adding my spec_helper file too if that helps. – Aaditi Jain Sep 21 '15 at 09:08
  • I have marked it as answer because it came the closest to my question and the bounty was closing today. However the reasoning is still missing. thanks :) – Aaditi Jain Sep 21 '15 at 09:24
  • This doesn't work for me. I added `ENV["RAILS_ENV"] ||= 'test'` in `spec_helper.rb` and it works – RoundOutTooSoon Jan 03 '18 at 02:30
5

Your rails_helper looks strange. The first line says:

Rails.env = 'test'

At the first line you don't have Rails loaded yet (I suppose you run RSpec using bundle exec rspec). So it should raise an error.

Therefore I made a small change in rails_helper:

require File.expand_path('../../config/environment', __FILE__)
Rails.env = 'test'
require 'spec_helper'
require 'rspec/rails'
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

# the rest

Now putting

expect(ActiveRecord::Base.connection_config[:database]).to match(/test/)

somewhere in your spec, should pass successfully.

Yule
  • 9,668
  • 3
  • 51
  • 72
dimakura
  • 7,575
  • 17
  • 36
  • I already have a `Rails.env = 'test'` in my rails helper (mentioned it in my question above). Earlier i had a `ENV['RAILS_ENV'] ||= 'test'` in my rails_helper and it did not set my env correclty. Hence I changed it to `Rails.env = 'test'` after suggestions on SO. (That helped. My env is now set correctly for test cases.) But it still hits the dev db and not test db. – Aaditi Jain Sep 11 '15 at 13:32
  • Can you add `ENV['RAILS_ENV'] ||= 'test'` just for checking in the first line? And where is Rails.env=`test` defined? Can you give full `rails_helper.rb`? – dimakura Sep 11 '15 at 13:42
  • Sure. I am adding rails_helper.rb in the question above. Thank you :) – Aaditi Jain Sep 11 '15 at 13:44
  • setting ` ENV['RAILS_ENV'] ||= 'test'` as first line of my rails_helper does not help. Instead it shows my 'Rails.env' shows as 'development' when I run Rspec (checked using pry) – Aaditi Jain Sep 11 '15 at 13:51
  • @AaditiJain I've updated my answer. But I'm curious how do you invoke RSpec? – dimakura Sep 11 '15 at 14:32
  • I use `rspec` command to run my test cases. Also I tried solution mentioned in your answer but it does not solve the problem. – Aaditi Jain Sep 14 '15 at 07:49
  • @AaditiJain So you clain `expect(ActiveRecord::Base.connection_config[:database]).to match(/test/)` did not pass? – dimakura Sep 14 '15 at 07:51
  • No it did not. Got this: `Failure/Error: expect(ActiveRecord::Base.connection_config[:database]).to match(/test/) expected "app_dev" to match /test/ Diff: @@ -1,2 +1,2 @@ -/test/ +"app_dev"` – Aaditi Jain Sep 14 '15 at 07:57
2

My answer applies to anyone who is using Rspec with Ruby outside of Rails. For example, let's say you are creating a Ruby gem. Well, you can still add a database.yml in a config folder in your project and specify a test option:

test:
  adapter: 'mysql2'
  encoding: utf8mb4
  collation: utf8mb4_bin
  pool: 1
  username: root
  password:
  host: localhost
  database: 'my_site_test'

Now you can add the following in spec_helper.rb:

  config.before :suite do
    ActiveRecord::Base.establish_connection(YAML.load(File.open(File.expand_path("../../lib/my_gem_config/database.yml", __FILE__)))["test"])
  end  

The :suite scope indicates that the block of code should be run once before the suite of tests, that means all of your tests.

Daniel Viglione
  • 8,014
  • 9
  • 67
  • 101
1

1) Add require: false to the declaration of 'rails-erd' gem

gem 'rails-erd', '~> 1.4.1', require: false

2) In your spec_helper.rb, replace Rails.env = 'test' by ENV['RAILS_ENV'] ||= 'test'

3) Verify in your bin/rspec (if present) that you don't have any instruction changing the value of env

4) Then stop spring from the command line

spring stop

5) Run your specs from the command line

rspec
Benjamin Bouchet
  • 12,971
  • 2
  • 41
  • 73
1

You can run rspc with RAILS_ENV=test bundle exec rspec spec

Also you can put inside rails_helper.rb

Rails.env = 'test'

Also move testing framework section from development test to test inside gemfile

group :test do
  # testing framework for rails
  gem 'rspec-rails', '~> 3.1.0'
  gem 'rspec-collection_matchers', '~> 1.1.2'
  gem 'factory_girl_rails', '~> 4.4.1'
  gem 'shoulda-matchers', '~> 2.8.0'

  # set of strategies for cleaning your database
  gem 'database_cleaner', '~> 1.3.0'
end
Arvind
  • 2,671
  • 1
  • 18
  • 32
0

Just put ENV["RAILS_ENV"] = "test" at the top of rails_helper

Arsen
  • 10,815
  • 2
  • 34
  • 46
  • 1
    No, that does not help :( . Also, as I have mentioned in the question, my `Rails.env` is set correctly to test during rspec (verified using pry). Thanks for looking :) – Aaditi Jain Sep 14 '15 at 09:53