"rake spec" migrates the database every time - ruby-on-rails

When I run any of the rspec tasks via rake, the database seems to be dropped and migrated, but if I run them via script/spec path/to/spec, it doesn't. Is there an option I can set so the rake spec doesn't touch the database?

It shouldn't be running any migrations, only importing db/schema.rb into your test database. This is the expected behavior so your tests use a fresh copy of the database schema before they run. What is your reasoning for not wanting it to refresh the test database?

For what I do I want it off permanently. So with rspec 2.5.0 and rails 3:
Copy rspec.rake to your apps /lib/tasks folder from:
~/.rvm/gems/ruby-1.8.7-p302/gems/rspec-rails-2.5.0/lib/rspec/rails/tasks/rspec.rake
Add this to the top of the file:
Rake::TaskManager.class_eval do
def remove_task(task_name)
#tasks.delete(task_name.to_s)
end
end
def remove_task(task_name)
Rake.application.remove_task(task_name)
end
remove_task 'spec'
Find and edit this line to force a noop:
spec_prereq = :noop #Rails.configuration.generators.options[:rails][:orm] == :active_record ? "db:test:prepare" : :noop

I had this same problem also when running rspec from the command line. In my cases I was working with an legacy database that had no migrations, so the tests would fail because migrations could not be run.
The solution was to edit the spec/spec_helper.rb file and delete the following line:
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
After that the tests ran without failing.

Related

rake task not running sub-tasks in order specified

In a rails 4.2 app, in Rakefile, I have this:
task(:default).clear
task :default => [:test, 'bundle:audit']
The output, always has bundle:audit running first. Why is that?
I read in some places that rake executes tasks as dependencies arise, but bundle:audit, as far as I can tell, does not depend on test. It is defined here:
https://github.com/rubysec/bundler-audit/blob/master/lib/bundler/audit/task.rb
To quote a comment discussing the same problem in Rake's GitHub repository:
It turns out that your problem is due to the way rails creates its test tasks:
desc "Run tests quickly by merging all types and not resetting db"
Rails::TestTask.new(:all) do |t|
t.pattern = "test/**/*_test.rb"
end
https://github.com/rails/rails/blob/v4.2.7.1/railties/lib/rails/test_unit/testing.rake#L24-L27
Here Rails uses Rails::TestTask for the test:all target which will load all test files.
def define
task #name do
if ENV['TESTOPTS']
ARGV.replace Shellwords.split ENV['TESTOPTS']
end
libs = #libs - $LOAD_PATH
$LOAD_PATH.unshift(*libs)
file_list.each { |fl|
FileList[fl].to_a.each { |f| require File.expand_path f }
}
end
end
https://github.com/rails/rails/blob/v4.2.7.1/railties/lib/rails/test_unit/sub_test_task.rb#L106-L118
But unlike Rake::TestTask, which immediately runs the tests, Rails::TestTask only requires the files necessary to run the tests then relies on the at_exit handler in Minitest to run the tests. This means rake dependencies are completely ignored for running tests.
I updated the links to the source code, because the discussion was about Rails 4.1.8, but the problem still exists the source code of Rails 4.2.7.1.
This problem was reported as an issue to the Rails team on GitHub and it was fixed in this PR.
That said: This problem should be fixed since Rails 5.0.0.

Why would capybara feature specs fail when run together, only for me. but pass when separately?

This would seem to be due to a local configuration problem but nothing I've tried has helped and I am stuck.
When I run our rspec-capybara feature spec called "user_save_quote" I got 5/8 failures. However when I run each of the (failing) line numbers individually they pass. Moreover when other developers run this spec in its entirety each test passes for them.
I've tried the following but none of them helped:
switching to the firefox driver
removing my .bashrc file
removing lastpass from Chrome
running specs from a non-tmux session
run with and without bundle exec prefix
rake db:migrate, rake db:seed and RAILS_ENV=test rake db:test:prepare
closing all apps and restarting my computer
The visual behavior in the application is to create a user and then login but a subsequent attempt to do those things just seems to hang for 10 seconds then fail.
I've tried switching to the firefox driver but it didn't help.
Try to add this to your spec helper.
It may be caused because user already created,and for next spec you are try to create it again
config.before do
DatabaseCleaner.start
end
config.after do
DatabaseCleaner.clean
end
and check your factory if you are use it,add sequence
FactoryGirl.define do
factory :user do |f|
f.sequence(:name) { |n| "sir-#{n}-#{rand(99999)}" }
f.sequence(:email) { |n| "sir#{n}#{rand(99999)}#example.com" }
end

How do I prepare test database(s) for Rails rspec tests without running rake spec?

After significant troubleshooting, I figured out that I needed to run rake spec once (I can abort with control-c) before I can run rspec directly (e.g. on a subset of our specs). We are running Rails 3.0.7 and RSpec 2.5.0.
Clearly, rake is running some important database setup tasks / code (we have custom code in the root level rails Rakefile and possibly other places).
How can I run the rake test database setup tasks / code without running rake spec?
In addition to being able to run rspec on a subset of files, I am using specjour to spread our specs across multiple cores (haven't had success with spreading them across the LAN yet), but I see the same behavior as for running rspec directly: I need to run rake spec on each test database (assuming two cores) before specjour works:
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 test (as is common for the parallel testing gems):
test:
adapter: postgresql
encoding: unicode
database: test<%=ENV['TEST_ENV_NUMBER']%>
username: user
password:
parallel_tests seems to set up its databases correctly, but many of our specs fail.
I should also mention that running specjour prepare causes Postgres to log errors that it can't find the databases, but it creates them (without tables). On a subsequent run, no errors are logged, but also no tables are created. It is possible that my whole issue is simply a bug in prepare, so I reported it on github.
I think that I can run arbitrary code on each specjour test database by setting Specjour::Configuration.prepare in .specjour/hooks.rb, so if there's any rake tasks or other code that I need to run, it may work there.
I would recommend dropping your test database, then re-create it and migrate:
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 specs:
bundle exec rspec spec
gerry3 noted that:
A simpler solution is to just run rake db:test:prepare
However, if you're using PostgreSQL this wont work because the rails environment gets loaded, which opens a database connection. This causes the prepare call to fail, because the DB cannot be dropped. Tricky thing.
I had a similar problem setting up the CI system at work, so I gradually worked up a system to handle this. It may not be the best solution, but it works for me in my situation and I'm always on the lookout for better ways to do things.
I have a test database that I needed setup, but also needed seeded data loaded for our tests to work.
The basics of troubleshooting rake tasks is to run rake with the --trace option to see what is happening under the hood. When i did this, I found that running rake spec did a number of things that I could replicate (or modify as I saw fit) in a custom rake task.
Here's an example of what we do.
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 only an example, and specific to our situation, so you'll need to figure out what needs to be done to get your test db setup, but it is quite easy to determine using the --trace option of rake.
Additionally, if you find the test setup is taking too long (as it does in our case), you can also dump the database into .sql format and have the test database pipe it directly into mysql to load. We save several minutes off the test db setup that way. I don't show that here because it complicates things substantially -- it needs to be generated properly without getting stale, etc.
HTH
The provided solutions all require to load the Rails environment, which is, in most cases, not the desired behaviour due to very large overhead and very low speed. DatabaseCleaner gem is also rather slow, and it adds another dependency to your app.
After months of chagrin and vexation thanks to reasons vide supra, I have finally found the following solution to be exactly what I need. It's nice, simple and fast. In spec_helper.rb:
config.after :all do
ActiveRecord::Base.subclasses.each(&:delete_all)
end
The best part about this is: It will only clear those tables that you have effectively touched (untouched Models will not be loaded and thus not appear in subclasses, also the reason why this doesn't work before tests). Also, it executes after the tests, so the (hopefully) green dots will appear right away.
The only downside to this is that if you have a dirty database before running tests, it will not be cleaned. But I doubt that is a major issue, since the test database is usually not touched from outside tests.
Edit
Seeing as this answer has gained some popularity, I wanted to edit it for completeness: if you want to clear all tables, even the ones not touched, you should be able to do something like the "hacks" below.
Hack 1 - pre-loading all models for subclasses method
Evaluate this before calling subclasses:
Dir[Rails.root.join("app", "models", "**", "*.rb")].each(&method(:require))
Note that this method may take some time!
Hack 2 - manually truncating the tables
ActiveRecord::Base.connection.tables.keep_if{ |x| x != 'schema_migrations' }
will get you all table names, with those 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
It appears that in Rails 4.1+, the best solution is simply to add ActiveRecord::Migration.maintain_test_schema! in your rails_helper after require 'rspec/rails'.
i.e. you don't have to worry about having to prepare the database anymore.
https://relishapp.com/rspec/rspec-rails/docs/upgrade#pending-migration-checks
In a spring-ified Rails 4 app, my bin/setup is usually augmented 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 the test DB, as
rake db:setup # Create the database, load the schema, and initialize with the seed data
(use db:reset to also drop the database first)
As the comment mentions, if we want to drop the DB first, rake db:reset does just that.
I also find that this provides more feedback when compared to rake db:test:prepare.
I started by dropping my test database
rake db:drop RAILS_ENV=test
when trying to create a new test database I ran into an issue because my user account was not the same as the account that owns the databases so I created the database in PostgreSQL instead.
type psql in the command prompt and then run the below to create a test database that uses an account other than your own.
CREATE DATABASE your_database_name OWNER your_db_owner;
then run your migrations in the test environment.
rake db:migrate RAILS_ENV=test

Rails: How to test code in the lib/ directory?

I have a model which gets its data from a parser object. I'm thinking that the parser class should live in the lib/ directory (although I could be persuaded that it should live soewhere else). The question is: Where should my unit tests for the parser class be? And how do I ensure that they are run each time I run rake test?
In the Rails application I'm working on, I decided to just place the tests in the test\unit directory. I will also nest them by module/directory as well, for example:
lib/a.rb => test/unit/a_test.rb
lib/b/c.rb => test/unit/b/c_test.rb
For me, this was the path of last resistance, as these tests ran without having to make any other changes.
Here's one way:
Create lib/tasks/test_lib_dir.rake with the following
namespace :test do
desc "Test lib source"
Rake::TestTask.new(:lib) do |t|
t.libs << "test"
t.pattern = 'test/lib/**/*_test.rb'
t.verbose = true
end
end
Mimic the structure of your lib dir under the test dir, replacing lib code with corresponding tests.
Run rake test:lib to run your lib tests.
If you want all tests to run when you invoke rake test, you could add the following to your new rake file.
lib_task = Rake::Task["test:lib"]
test_task = Rake::Task[:test]
test_task.enhance { lib_task.invoke }
I was looking to do the same thing but with rspec & autospec and it took a little digging to figure out just where they were getting the list of directories / file patterns that dictated which test files to run. Ultimately I found this in lib/tasks/rspec.rake:86
[:models, :controllers, :views, :helpers, :lib, :integration].each do |sub|
desc "Run the code examples in spec/#{sub}"
Spec::Rake::SpecTask.new(sub => spec_prereq) do |t|
t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
end
end
I had placed my tests in a new spec/libs directory when the rpsec.rake file was configured to look in spec/lib. Simply renaming libs -> lib did the trick!
An easy and clean way is just to create a directory under test/unit/lib. Then create test as test/unit/lib/foo_test.rb corresponding to lib/foo.rb. No new rake tasks required, and you can nest more directories if needed to match the lib directory structure.
As of Rails 4.0:
rake test:all # Run all tests in any subdir of `test` without resetting the DB
rake test:all:db # Same as above and resets the DB
As of Rails 4.1, redefine test:run to include additional tasks when running rake or rake test:
# lib/tasks/test.rake
namespace :test do
Rake::Task["run"].clear
task run: ["test:units", "test:functionals", "test:generators", "test:integration", "test:tasks"]
["tasks"].each do |name|
Rails::TestTask.new(name => "test:prepare") do |t|
t.pattern = "test/#{name}/**/*_test.rb"
end
end
end
This has the added bonus of defining rake test:tasks in the given example.
As of Rails 4.2, test:run includes all subdirs of test including them when running rake test, and thus rake.
To not define additional rake tasks to run tests from the custom defined folders you may also run them with the command rake test:all. Tests folders structure for the lib folder or any other custom folder is up to you. But I prefer to duplicate them in classes: lib is matched to test/lib, app/form_objects to test/form_objects.
Use:
[spring] rake test:all
to run all tests, including the directories you created (like [root]/test/lib/).
Omit [spring] if tou aren't using it.

Where does Rails store data created by saving activerecord objects during tests?

Where does Rails store data created by saving activerecord objects during tests?
I thought I knew the answer to that question: obviously in the _test database. But it looks like this is not true!
I used this system to test what's happening to saved ActiveRecord data during rspec tests:
$ rails -d mysql test
$ cd test
$ nano config/database.yml ...
... create mysql databases test_test, test_development, test_production
$ script/generate rspec
$ script/generate rspec_model foo
edit Foo migration:
class CreateFoos
$ rake db:migrate
edit spec/models/foo_spec.rb:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe Foo do
before(:each) do
#valid_attributes = {
:bar => 12345
}
end
it "should create a new instance given valid attributes" do
foo = Foo.new(#valid_attributes)
foo.save
puts "sleeping..."
sleep(20)
end
end
$ rake spec
When you see "sleeping...", change to another open terminal with a mysql session conneted to the test_test database and do:
mysql> select * from foos;
Empty set (0.00 sec)
Why doesn't the mysql session show any records in the test_test database while the test is running?
Items in the test database are erased by default after each test is run, by design. This is done to make sure that each of your tests has its own sandbox to play in that doesn't cause any interactions with the tests before it.
Again, this is by design. You don't want tests that are manipulating the same set of data (or rely on synchronous execution), because there is no guarantee of execution order.
However, I believe if you modify you test/test_helper.rb file to say this:
self.use_transactional_fixtures = false
instead of
self.use_transactional_fixtures = true
It will cause the data in your test database to persist.
ALSO: My advice is specifically designed to work with Test::Unit, not RSpec. However, I imagine that there is a similar setting your spec_helper.rb you should be looking for.
You can observe records being added to the test database with:
tail -f log/test.log
You should see the transactions flying by as the tests are run.
"But why does the mysql query show no data in the database while the test is running?"
Because it's in a transaction. If you turn transactional fixtures off your tests will run much slower than before.

Resources