How to prevent "rake test" from deleting "rake db:seed" data? - ruby-on-rails

My Ruby version is ruby 1.9.3p385 . My Rails version is 3.2.12.
I use the following to load the test database:
rake db:seed RAILS_ENV=test
Everything works great. All the Factory Girl stuff is loaded nicely.
Contents of test/factories.rb contains the factories. The contents of db/seeds.rb is simply:
FactoryGirl.create(:music_categorization)
FactoryGirl.create(:dance_categorization)
Now, when I run the tests using the following command:
rake test
Rails deletes all the seed data and the tests fail. I'd like a way to prevent "rake test" from deleting data.
The other route I went was to load the seed data as part of the "rake test" command as mentioned in this question. However, what that ends up doing is loading the test data twice (basically db/seeds.rb is called twice for some reason). I abandoned that route and now simply want to do the following to run my tests:
rake db:seed RAILS_ENV=test
rake test
Any help is appreciated. I basically want to prevent rake test from deleting my data OR figure out a way to not have db/seeds.rb called twice.

AFAIK its not usual to use db:seed to load data for your tests, its normally just used to load seed data for development purposes only.
Instead you should create test data in the actual test file. Usually test data is deleted after each test using something like database_cleaner, so each test starts with an empty database.
For example in rspec you can load test data in a let block, before block or in the test itself, e.g
require 'spec_helper'
describe Page do
let(:user) { FactoryGirl.create(:user) }
before do
# create some data
end
it '#name returns XYZ' do
page = FactoryGirl.create(:page, :user => user)
page.description.should == 'XYZ'
end
it '#description returns ABC' do
page = FactoryGirl.create(:page, :user => user)
page.description.should == 'ABC'
end
end

First, let me just say that in general you should not be using seed data in your tests. Tests are supposed to run with an empty database, and you create only the data you need for each test.
In your case, you seem to have not understood the meaning of the seed data, which is basically core data that your application needs to work properly. If you need to instantiate a couple of models in your tests, simply do (assuming you're using rspec)
before(:each) do
FactoryGirl.create(:music_categorization)
FactoryGirl.create(:dance_categorization)
end
If you still want to run the tests with the seed data, you can always try and run rspec, which will just run all you rspec examples leaving the test database as is. But believe, that's not what you want.

Related

Records created in Rspec aren't available in new threads?

In Rspec, I'm creating records, e.g. let!(:user) { create(:user) }.
I can access the new user in Rspec and in the main thread of the subject. Both of these return the user:
puts User.all.to_a
puts ActiveRecord::Base.connection.exec_query('select * from users')
However, I can now longer access the user in a new thread:
Thread.new do
puts User.all.to_a
puts ActiveRecord::Base.connection.exec_query('select * from users')
end
How do I fix this? Is this just an Rspec issue? I don't think I can reproduce it in Rails console.
You have probably configured RSpec to run its test within a database transaction
Quote from the RSpec Docs:
>
When you run rails generate rspec:install, the spec/rails_helper.rb file
includes the following configuration:
RSpec.configure do |config|
config.use_transactional_fixtures = true
end
The name of this setting is a bit misleading. What it really means in Rails
is "run every test method within a transaction." In the context of rspec-rails,
it means "run every example within a transaction."
The idea is to start each example with a clean database, create whatever data
is necessary for that example, and then remove that data by simply rolling back
the transaction at the end of the example.
You might want to disable this configuration when your application tests have the requirement to support multiple threads at the same time.
But that means that your test database will not be cleared from test data automatically anymore when a test is done. Instead, you will need to delete the test data manually or use another gem (like database_cleaner) to reset the database after running tests.

Where do I put seed data if I have already created my database in my Rails project?

I’m using Rials 4.2.5. I want to create some seed data for a new model, user_images, I just created in an existing project. However, I already have a db/seeds.rb file that has been run on my database. Where do I put the seed data for this new model? I assume i can’t use db/seeds.rb because it has already been run. It is not an option to blow away the database and start again.
Thanks, - Dave
You can use seeds.. I use, for example:
Person.find_or_create_by(name: 'Bob')
Lots of them, as required, then run as many times as I like.. I run seeds on each auto deployment for example, so I don't forget..
Link to command: http://apidock.com/rails/v4.2.1/ActiveRecord/Relation/find_or_create_by
create a custom rake task in lib/tasks. The file should end in .rake. Then you run it by the name. For example:
task :do_something => :environment do
p "do something"
end
You'd run this task by calling rake do_something in terminal.

Rails, be a pal and reset the database between test suites

Work is transitioning from Rails 3 to Rails 4. Everything seems to be running more or less smoothly on the development side, but testing results in a multitude of varying failures when all suites - units, functionals, and integration - are run in one go with rake:test.
What's interesting is that running each of these suites individually produces no failures. This strongly suggests that the database is not resetting for our tests in Rails 4 quite the way it was in Rails 3.
I've tried overriding the rake:test task to execute db:test:prepare prior to running each suite, but this apparently doesn't do what I think it does, or rather, what I want it to do, which is to work with a fresh set of data for each test and therefore succeed or fail independently of every other test - the way it (was or should have been) in our Rails 3 setup.
Why is this happening? How might I fix it?
(Note that the testing framework is vanilla Rails with fixtures and the like. The testing failures we're getting are usually foreign key errors or failures for data to change in expected ways that don't show up when the DB is reset before a testing suite.)
EDIT:
Here are the changes I'm making to my Rakefile. The idea is to get rake:test to perform as it would in Rails 3, with the exception of properly resetting the database between unit, functional, and integration suites.
# /Rakefile
task :test => [];
Rake::Task[:test].clear
task :test do
puts Rails.env
if Rails.env == "test"
puts "units"
# Rake::Task["db:drop"].execute - results in 'test database not configured' error
# Rake::Task["db:reset"].execute - results in 'relation 'table' does not exist' error
Rake::Task["db:create"].execute
Rake::Task["db:migrate"].execute
Rake::Task["test:units"].execute
puts "functionals"
Rake::Task["db:schema:load"].execute
Rake::Task["test:functionals"].execute
puts "integration"
Rake::Task["db:schema:load"].execute
Rake::Task["test:integration"].execute
end
end
EDIT 2:
Rails version 4.1.8
Here is my test_helper. I've omitted helper methods that don't work with our data since I'm probably not allowed to share them and they're irrelevant to how the testing database is loaded.
Note also that we have a custom schema.rb from which the testing data are generated, as well, since trying to create them from migrations does not support some of the custom functionality/behavior we want in the end product, like materialized views. Redacted stuff will be enclosed in <<>>.
#test_helper.rb
ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
include ActionDispatch::TestProcess
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
set_fixture_class <<cached_object>>: ResultsDb::<<DesiredObjectClass>>Cache
fixtures :all
# Add more helper methods to be used by all tests here...
def reload_contig(contig_sym)
contig = contigs(contig_sym)
src = contig.src
new_tig = Contig.new(
org: contig.org,
version: contig.version,
size: contig.size,
sha1: contig.sha1,
active: contig.active,
src_id: src.id,
src_type: contig.src_type)
new_tig.id = contig.id
contig.destroy
unless new_tig.save
raise new_tig.errors.full_messages.inspect
end
src.contigs << new_tig
src.save
new_tig
end
def reload_coord(coord_sym)
coord = coords(coord_sym)
new_coord = Coord.new(
:mapped_id => coord.mapped_id,
:mapped_type => coord.mapped_type,
:contig_id => coord.contig_id,
:contig_type => coord.contig_type,
:start => coord.start,
:stop => coord.stop,
:fwd_strand => coord.fwd_strand
)
new_coord.id = coord.id
coord.destroy
new_coord.save!
end
end
You might have a look at the DatabaseCleaner gem that is specifically designed to assist you with database consistency and cleanliness during testing in Rails.
I've only run into problems when my code bypasses ActiveRecord and manipulates the data directly. In all other cases this gem has worked very well for me for testing.
Assuming you are currently on Rails 4.0, your current approach is about the best you can do if you can't add the database_cleaner gem. (I would suggest that you prefer db:schema:load to db:migrate throughout—there's no reason ever to run through all the migrations from the start in the test environment, unless you've done something unusual with them.) But once you get to Rails 4.1 or higher, you've got a better solution available.
Starting with Rails 4.1, management of the test database schema was automated, and rake db:test:prepare was deprecated. If you regenerate your test_helper.rb at this point, everything should work magically.
Have you tried adding either of these in your overriding of rake:test?
rake db:reset db:migrate
or
rake db:drop db:create db:migrate
The question seems similar to this one. I know I've always built my own rake db:recreate that does this sort of thing for test data.

How to auto-load data in the test database before to test my application?

I am using Ruby on Rails 3.0.9 and RSpec 2. I would like to auto-load seed data in the test database before I tesst my application. That is, at the testing start up time (when I run tests) I would like to "auto-populate"\"auto-boot" the test database.
How can I populate the database with seed data?
P.S.: As I read around, (maybe) I should populate the test database by adding some code to the /spec/spec_helper.rb file... but what code and how?
In my task/custom.rake file I have:
namespace :test do
desc "Boot database"
task :boot => [:load, :seed] do
end
desc "Reboot database"
task :reboot => [:purge, :boot] do
end
end
If you'd like to just invoke the seed rake task, I'd do something like this:
ENV['RAILS_ENV'] = 'test'
Rake::Task["db:seed"].invoke
But, I'd recommend using Fixtures (http://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures).
Or even better a fixture replacement like Factory Girl (https://github.com/thoughtbot/factory_girl), whereby you can load dummy data with all the associated data. This is a much less brittle approach.

A question in the rails spec test

Today, I use the factory_girl instead of the rails fixtures, but i get a problem:
After I run the command "spec spec" done, the data resets to the fixtures, who can tell me the answer?
thank you!
If you intend to use both factories and fixtures in your project and not running them through the rake tasks: eg rake spec, you will need to make sure that you are doing removal of the values from the db by hand. its likely what you are doing is just grabbing an old record in the database and you think the data is being reset. You can verify this by using puts inside your spec to trace the number of records in the db.
puts MyRecord.count
You can clear values in an after or before block.
before(:each) do
Factory(:my_model)
end
after(:each) do
MyModel.delete_all
end
if you intend to use this model or factory in other spec files, you can add these to global before and after blocks in the spec helper.

Resources