Prevent rake task dependency from loading Rails twice - ruby-on-rails

Following the example at http://robots.thoughtbot.com/testing-your-factories-first
the line task spec: :factory_specs in the Rakefile tells rake to execute "factory_specs" task before "spec" task.
My issue is that rake spec loads the Rails environment twice, one to execute factory_specs task and then another to execute spec task.
How do I prevent my rake command from loading Rails twice?
My stack:
Ruby 1.9.3p484
Rails 3.2.13

With the latest version of FactoryGirl, you can use FactoryGirl.lint instead of explicitly testing your factories in a separate rake task. Just update to the latest version and add this to your spec_helper.rb:
RSpec.configure do |config|
config.before(:suite) do
FactoryGirl.lint
end
end
More info is in the Getting Started Guide.

Related

When switching from Minitest to RSpec in Rails, how to make `rails test` (or `rake test`) run the RSpec tests?

When adding RSpec to Rails, we can finally run rails spec (or bundle exec rspec) to run the RSpec tests.
However, rails test confusingly still attempts to run the (non-existent) Minitest tests.
How can the "test" rake task be configured to run the RSpec tests instead?
You can override the test task like this:
# Add the code below in the Rakefile
require File.expand_path(‘config/application’, __dir__)
Rails.application.load_tasks
Rake::Task['test'].clear
task :test do
Rake::Task['rspec’].invoke
end
Another way (I only tried in my console with a task that puts something but it should work with rspec):
# Add the code below in the Rakefile
require File.expand_path(‘config/application’, __dir__)
Rails.application.load_tasks
task(:test).clear.enhance([‘rspec’])

How to invoke RSpec inside a rake task?

We wrote some tests that are necessary, but very slow. So we configured RSpec to exclude them except on Solano, where we set up an ENV variable.
# spec_helper
unless ENV['RUN_ALL_TESTS'] == 'true'
config.filter_run_excluding :slow
end
That works, but I'm trying to write a rake task we can call to run every test locally by setting that same ENV variable and then running the suite. I'm having trouble figuring out how to trigger RSpec. This is what I've got now:
# all_tests.rake
require 'rspec/core/rake_task'
desc 'Run all tests, even those usually excluded.'
task all_tests: :environment do
ENV['RUN_ALL_TESTS'] = 'true'
RSpec::Core::RakeTask.new(:spec)
end
When I run it, it doesn't run any tests.
Most of the stuff I found is for triggering a rake task inside of a test, testing a rake task, or setting up a Rakefile. We're using rspec-rails, our default rake task is already set up.
To run RSpec through its rake integration, you need to both define a task and invoke it:
# all_tests.rake
require 'rspec/core/rake_task'
# Define the "spec" task, at task load time rather than inside another task
RSpec::Core::RakeTask.new(:spec)
desc 'Run all tests, even those usually excluded.'
task all_tests: :environment do
ENV['RUN_ALL_TESTS'] = 'true'
Rake::Task['spec'].invoke
end
Rake::Task['spec'].invoke did nothing when you tried it because rake turns a task name which is not a name of a defined task but is a file name into a Rake::FileTask, both on the command line and in Rake::Task. You had no 'spec' task defined, but you have a spec directory, so rake spec ran without error and did nothing.
I had a similar problem where bundle exec rake default would properly create an RSpec::Core::RakeTask, but bundle exec rake spec would instead create a a Rake::FileTask on the spec directory, with with bundle exec rake spec --trace outputting:
** Invoke spec (first_time, not_needed)
It turned out that rspec-rails was in the :test gem group, where it needed (per the docs) to be in both :test and :development.
Interestingly (?), once I did that, gems that had previously only been in the :test group were also available from the specs even when launched with RAILS_ENV=development. I assume that rspec-rails engages in some magic environment shenanigans behind the scenes.

Rails - Rake test and rubocop in one task

I'm trying to setup my rails project so that all the verification required by a contributor is in one command, currently we have been running:
rake test
But now we also want to use rubocop for static analysis:
rubocop -R -a
I want this to be executable in one simple rake task. It would be nice to override 'rake test' to run rubocop then the standard rake test stuff for a rails project, as then no-one will have to remember to change the command. But if I have to create a separate rake task, that's probably fine too.
I've seen the rubocop rake integration here, at the bottom, but I'm not sure how to bundle that with 'rake test' into one task... Any thoughts?
I prefer to set my default task to run rubocop then the tests. Either way, it is a good idea to have those tasks separate rather than have one task do two things.
require 'rubocop/rake_task'
task :default => [:rubocop, :test]
desc 'Run tests'
task(:test) do
# run your specs here
end
desc 'Run rubocop'
task :rubocop do
RuboCop::RakeTask.new
end
Your tasks:
> rake -T
rake rubocop # Run rubocop
rake test # Run tests
This is the .rake file that I ended up with in the end.
desc 'Run tests and rubocop'
task :validate do
Rake::Task['rubocop'].invoke
Rake::Task['test'].invoke
end
task :rubocop do
require 'rubocop'
cli = Rubocop::CLI.new
cli.run(%w(--rails --auto-correct))
end
You could easily define your own rake task which first invokes Rails' test rake task and then the code snippet you mentioned for rubocop.
For example, in a .rake file you could have something like that:
require 'rubocop/rake_task'
desc 'Run tests and rubocop'
task :my_test do
Rake::Task['test'].invoke
RuboCop::RakeTask.new
end
If you feel the need to customize the call to Rubocop and that involves more code, you could create another custom task, say :rubocop, which you then invoke from :my_test as well.
Finally, an alternative to creating your own rake task and sticking with rake test would be to modify your test_helper to invoke whatever you need invoked after testing is completed.
It appears to have changed from:
Rubocop::RakeTask.new
to:
RuboCop::RakeTask.new
See ma? I know how to CamelCase!
I used following .rake file to run the test and rubocop tasks at once:
task default: %w[rubocop test]
RuboCop::RakeTask.new(:rubocop) do |task|
task.patterns = ['**/*.rb']
task.fail_on_error = false
task.options = ["--auto-correct-all"]
end
task :test do
ruby 'test/program_test.rb'
end
The first line allows both tasks to be run by calling rake.
Command line arguments can also be added in the options array.

How to run a rake task right after rspec initializes the database

I have a Rails 2.2 app that I'm supporting and one thing that needs to be done before the app start is a small rake task to initialize and make sure the database is properly set. How can I get this task run right after rspec initializes the database. I run rspec using the rails spec command.
You could put a simple system call to your spec_helper.rb file.
An Example could look like this
# run rake task
`rake your_task RAILS_ENV=test`
RSpec.configure do |config|
...
end

MIgrations and Rspec

I'm developing a Rails application with Rspec for unit testing.
Weeks ago, Rspec used to migrate the database to the last version automatically when executing 'rake spec', but now it doesn't do it automatically, I have to implement everything for myself.
This happens in test environment, because my development data doesn't desappear.
Is my fault? I didn't change anything, I think :)
Typically what I do is use an alias command that runs both migrate and prepares the test database.
rake db:migrate && rake db:test:prepare
In your .bashrc just create an alias command like so and then run migrate_databases whenever you need to.
alias migrate_databases='rake db:migrate && rake db:test:prepare'
My solution for Rails 4:
in spec/spec_helper.rb or anywhere in testing environment initialization code:
# Automigrate if needs migration
if ActiveRecord::Migrator.needs_migration?
ActiveRecord::Migrator.migrate(File.join(Rails.root, 'db/migrate'))
end
UPD: As Dorian kindly pointed out in comments, you don't need to check separately if there are any pending migrations, because ActiveRecord::Migrator.migrate already does this behind the scenes. So you can effectively use just this one line:
ActiveRecord::Migrator.migrate(File.join(Rails.root, 'db/migrate'))
Rails 4.1 forward you can use:
ActiveRecord::Migration.maintain_test_schema!
Add at the top of your spec_helper.rb or rails_helper.rb and you're good to go. More info here.
Here's my workaround:
Rakefile:
require File.expand_path('../config/application', __FILE__)
require 'rake'
require "rspec/core/rake_task"
MyApp::Application.load_tasks
desc "Run specs"
RSpec::Core::RakeTask.new(:spec)
task :run_specs => ['db:test:clone', :spec] do
end
task :default => :run_specs
Then I run $ rake run_specs
for some reason default task doesn't default to run_specs
See if you have the following in your spec_helper.rb? Everytime you run specs, RSpec checks if there are pending migrations.
#Checks for pending migrations before tests are run.
#If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
This works even when Rails is not loaded and only does one SQL query most of the time.
if defined?(ActiveRecord::Migrator)
ActiveRecord::Migrator.migrate(File.join(Rails.root, 'db', 'migrate'))
end

Resources