How to prepare a test base for Rails rspec tests without using the rake specification?

After much troubleshooting, I realized that I need to run rake spec once (I can interrupt with control-c) before I can run rspec directly (for example, in a subset of our specifications). We are launching Rails 3.0.7 and RSpec 2.5.0.

Obviously, rake runs some important database configuration tasks / code (we have custom code on the Rakefile root level rails and possibly elsewhere).

How to run rake test database installation tasks / code without running rake spec ?

In addition to being able to run rspec in a subset of files, I use specjour to distribute our specifications on several cores (have not yet had time to distribute them on a local network), but I see the same behavior as for directly launching rspec: I need to run rake spec in each test database (assuming two cores) before specjour runs:

 rake spec TEST_ENV_NUMBER=1 control-c (after tests start) rake spec TEST_ENV_NUMBER=2 control-c (after tests start) specjour 

Note. my config / database.yml has this entry for the test (as is usually the case for parallel tests):

 test: adapter: postgresql encoding: unicode database: test<%=ENV['TEST_ENV_NUMBER']%> username: user password: 

parallel_tests seems to have configured its databases correctly, but many of our specs fail.

It should also be mentioned that running specjour prepare causes Postgres to log errors, that it cannot find the databases, but creates them (without tables). At the subsequent start of errors are not registered, but also tables are not created. It is possible that my whole problem is just a mistake in prepare , so I reported this to github.

I think I can run arbitrary code in every specjour test database by setting Specjour::Configuration.prepare to .specjour / hooks.rb, so if there are any rake tasks or other code that I need to run, it can work there.

+65
ruby-on-rails ruby-on-rails-3 rspec rspec2 specjour
May 6 '11 at 19:29
source share
5 answers

I had a similar problem with setting up the CI system at work, so I gradually developed a system for this. This may not be the best solution, but it works for me in my situation, and I am always on the lookout for better ways to do something.

I have a test database in which I need setup, but I also need uploaded data for our tests.

The basics of troubleshooting is to run rake with the --trace option to see what happens under the hood. When I did this, I found that the working rake spec did a few things that I could replicate (or modify, as I understood) in the rake user command.

Here is an example of what we are doing.

 desc "Setup test database - drops, loads schema, migrates and seeds the test db" task :test_db_setup => [:pre_reqs] do Rails.env = ENV['RAILS_ENV'] = 'test' Rake::Task['db:drop'].invoke Rake::Task['db:create'].invoke result = capture_stdout { Rake::Task['db:schema:load'].invoke } File.open(File.join(ENV['CC_BUILD_ARTIFACTS'] || 'log', 'schema-load.log'), 'w') { |f| f.write(result) } Rake::Task['db:seed:load'].invoke ActiveRecord::Base.establish_connection Rake::Task['db:migrate'].invoke end 

This is just an example and typical of our situation, so you need to figure out what needs to be done to get the db test setup, but it is quite easy to determine using the -trace rake option.

In addition, if you find that the test installation takes too much time (as in our case), you can also dump the database into .sql format and directly load the test database into mysql for download. We save a few minutes after installing the test db this way. I do not show it here because it significantly complicates the situation - it must be created correctly without becoming obsolete, etc.

NTN

+11
May 7 '11 at 16:48
source share

I would recommend resetting your test database, then re-creating it and doing the migration:

 bundle exec rake db:drop RAILS_ENV=test bundle exec rake db:create RAILS_ENV=test bundle exec rake db:schema:load RAILS_ENV=test 

After these steps, you can run your specifications:

 bundle exec rspec spec 

gerry3 noted that:

A simpler solution is to simply run rake db:test:prepare

However, if you use PostgreSQL, this will not work because the rail environment is loading, which opens a connection to the database. This causes the prepare call to fail because the database cannot be dropped. The hard thing.

+122
Jun 22 2018-12-12T00:
source share

All proposed solutions require loading the Rails environment, which in most cases is not the desired behavior due to very high overhead and very low speed. DatabaseCleaner gem is also quite slow, and it adds another dependency to your application.

After much grief and frustration for the reasons given above, I finally found the following solution exactly in what I needed. It is good, simple and fast. In spec_helper.rb :

 config.after :all do ActiveRecord::Base.subclasses.each(&:delete_all) end 

The best part is this: it will clear only those tables that you have effectively touched (pristine models will not be loaded and therefore will not appear in subclasses , also the reason why this does not happen before ). In addition, it is performed after tests, so green dots (hopefully) will be displayed immediately.

The only drawback to this is that if you have a dirty database before running the tests, it will not be cleared. But I doubt that this is a serious problem, since the test database usually does not apply to external tests.

Edit

Having seen that this answer gained some popularity, I wanted to edit it for completeness: if you want to clear all tables, even those that have not been touched, you should do something like “hacks” below.

Hack 1 - preload all models for subclasses method

Evaluate this before calling subclasses :

 Dir[Rails.root.join("app", "models", "**", "*.rb")].each(&method(:require)) 

Please note that this method may take some time!

Hack 2 - manual truncation of tables

 ActiveRecord::Base.connection.tables.keep_if{ |x| x != 'schema_migrations' } 

you will get all the table names with which you can do something like:

 case ActiveRecord::Base.configurations[Rails.env]["adapter"] when /^mysql/, /^postgresql/ ActiveRecord::Base.connection.execute("TRUNCATE #{table_name}") when /^sqlite/ ActiveRecord::Base.connection.execute("DELETE FROM #{table_name}") ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence where name='#{table_name}'") end 
+13
Aug 04 '13 at 3:37 on
source share

It seems that in Rails 4.1+, the best solution is to simply add ActiveRecord::Migration.maintain_test_schema! in rails_helper after require 'rspec/rails' .

i.e. You do not need to worry about the need to prepare the database.

https://relishapp.com/rspec/rspec-rails/docs/upgrade#pending-migration-checks

+4
May 20 '15 at 10:00
source share

In a spring Rails 4-enabled application, my bin/setup usually added to contain

 puts "\n== Preparing test database ==" system "RAILS_ENV=test bin/rake db:setup" 



This is very similar to leviathan's answer , plus seeding a test db like

rake db:setup # Create a database, load the schema, and initialize the seed data
(use db:reset to delete the database first)

As noted in the comment, if we want to reset the database first, rake db:reset will do just that.

I also found that this gives more feedback than rake db:test:prepare .

+3
Jul 07 '15 at 19:56
source share



All Articles