Running Rake tasks in Rspec Tests - ruby

I am building up an integration test suite and there is one bit of logic that I need to have a clean database for. How can I run the db:test:purge task inside of one of my tests?
I am using: ruby 1.9.2, rails 3.0.9, rspec 2.6

You can invoke Rake tasks as following:
require 'rake'
Rake::Task[name].invoke
In this case this would result in the following code:
require 'rake'
Rake::Task['db:test:purge'].invoke

Approved answer didn't work for me, when I needed to execute my own rake task
Here's my solution
Put in the top of the spec file
require 'rake'
Place these lines where you need to execute your custom rake task, e.g. rake update_data from the file example.rake
load File.expand_path("../../../lib/tasks/example.rake", __FILE__)
# make sure you set correct relative path
Rake::Task.define_task(:environment)
Rake::Task["update_data"].invoke
My environment:
rails (4.0.0)
ruby (2.0.0p195)
rspec-core (2.14.7)
rspec-expectations (2.14.3)
rspec-mocks (2.14.4)
rspec (2.14.1)
rspec-rails (2.14.0)

If we require to use multiple rake tasks we can add
require "rake"
Rails.application.load_tasks
Then simply call any task.
Rake::Task['sync:process_companies'].invoke
Though I cant confirm if its slower because it loads all the tasks

for me (rails-6)
Rails.application.load_tasks
Rake::Task['app:sync'].invoke
=> require not necnessary in my case

We need to require the task also
require 'rake'
Rake.application.rake_require 'tasks/new_adapter'
After this, just call the task
Rake::Task['new:adapter'].invoke

Many of the above answers worked for me for running a single spec. However, I had to take an extra step when running multiple specs for a single rake task.
After each spec, I had to run Rake::Task.clear, as (for some reason) the task would not be run again if it was registered as being already_invoked (i.e. if Rake::Task['my_task'].already_invoked returned true.
I added the following line to my rake task spec:
after { Rake::Task.clear }
and everything worked as expected when running multiple tests for the same rake task.

Related

"Rake cannot load such file" error in Sinatra app

I am building a Sinatra app and trying to use ActiveRecord. Rake is not recognizing my controller file and returning rake aborted! LoadError: cannot load such file whenever I run any rake task. Here are my gems:
source "https://rubygems.org"
ruby "2.7.2"
gem 'sinatra'
gem 'thin'
gem 'shotgun'
gem 'require_all'
gem 'activerecord'
gem 'sinatra-activerecord'
gem 'sqlite3'
gem 'rake', '~> 13.0.6'
And here's the Rakefile:
# Rakefile
require 'sinatra/activerecord/rake'
require_relative './app/test_controller.rb'
Any ideas? In the Rakefile, I've tried require_relative for ./app, /app, ../app, etc. Also, I'm on a bit of a time crunch, so if I can't sort this out quickly do I need Rake to use ActiveRecord?
TL/DR:
remove require_relative './app/test_controller.rb' from your Rakefile.
Details:
Rake is a tool that lets us define and run commands from the command line (e.g. rake db:migrate). Activerecord comes bundled with a few rake tasks (like generating a migration file, running one, dumping/loading your database schema, etc) that make it much easier to work with.
Rake tasks are just ruby, so to run a Rake task successfully it will need to load any classes/files it depends on (which is typically handled independently by each rake task). If you're going to write your own rake tasks you'll want to ensure that the tasks require the relevant files. Loading your app (or sinatra controllers) in a base Rakefile wouldn't generally be advised as it wouldn't always be needed.
The exception to this would be if you needed to load some kind of 'boot' or 'config' file in order to setup your database connections/configuration so that the activerecord rake tasks could successfully connect to your database.

Old version of minitest used when running unit tests through rake

I have some classes with unit tests and I have a rake task to run these unit tests. However, I'm running into a problem where when the tests are run via rake an old version of minitest is being used. How can I get rake to use the newer version?
If I use the Minitest::Test subclass it runs fine when the tests are directly run through the ruby
command-line. However, if I use the following rake task:
require 'rake/testtask'
Rake::TestTask.new do |t|
t.pattern = 'tests/**/*_test.rb'
end
When I check the minitest version using puts MiniTest::Unit::VERSION it prints 5.5.0 when run with ruby, but prints 4.3.2 when run with rake. (When using gem list minitest -d version 4.3.2 is listed as the default.)
The reason I want to use the newer version of minitest is that when I directly run the unit tests using Ruby 2.0 I get the following warning:
MiniTest::Unit::TestCase is now Minitest::Test.
However, if I change MiniTest::Unit::TestCase to Minitest::Test I get the following error when I run the tests using rake.
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rake/ext/module.rb:36:in `const_missing': uninitialized constant MiniTest::Test (NameError)
from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/minitest/unit.rb:28:in `const_missing'
I want to avoid requiring any changes to the system configuration, because I want these tests to run on the default OS X ruby installation.
Using gem 'minitest', '=5.5.0' does not change the version of minitest that gets used.
Possibility #1: Run Rake with bundle exec to force it to use the version of Minitest managed by Bundler:
bundle exec rake test
Possibility #2: Create a binstub for Rake for your project that will load your bundle automatically:
bundle binstub rake
After that, you should be able to run Rake without bundle exec to get the same result.
Caveat: This has worked for the Ruby environment managers I've used recently, but you might need to Google around for a solution if it doesn't work for you.
Ruby is having a hard time loading minitest from the gem instead of the standard library, so we need to give it a little help. Add the following to your helper or rake task:
gem "minitest"
That will tell ruby to use the gem version. Just be sure to add that before minitest is required.

Rspec rake task gem no longer importing

Pulling my hair out on this. I'm running some rspec specs through rake using rspec's rake task. Its been working fine until I started getting this error message:
rake aborted!
LoadError: cannot load such file -- rspec/core/rake_task
Here is the results of gem list | grep rspec
rspec (3.1.0)
rspec-core (3.1.7)
rspec-expectations (3.1.2)
rspec-mocks (3.1.3)
rspec-support (3.1.2)
and here is the line I'm using to include the rake task in my Rakefile
require 'rspec/core/rake_task'
I uninstalled all rspec gems and re-installed. Same error. As I mentioned I've been running these tests for a few months now without issue. There have been no changes to the environment and it runs in a VM so I can ensure it wasn't a coworker. What am I missing?
EDIT
I double checked my Gemfile.lock file all the gem versions are matching with the one in the upstream repo.
First off, I recommend running your specs through the rspec command. It's far more flexible than running specs through rake and has less overhead. Running the specs through rake is still useful as part of a build pipeline (the kind of thing rake is good at).
You haven't provided sufficient information to definitely answer your question, but I can provide some suggestions:
Are you running rake via bundle exec rake? Bundler is designed to manage the load path at runtime after it installs your gems, and should ensure that the installed rspec-core/lib is on your load path.
You can add puts $LOAD_PATH.join("\n") to the top of your Rakefile to see what the load path is. Is rspec-core in the list anywhere? (I suspect it's not). If it's not, then require 'rspec/core/rake_task' is not going to work unless rspec-core is installed as a system gem. Use gem which rspec-core to see if it's installed that way.

Adding a gem dynamically from within a rake task

I am trying to use the mongo gem for a data migration rake task. I don't want to add it to the Gemfile for the whole project just so it can be used from this single rake task. How do I dynamically add mongo to the bundle for just that rake task?
I have tried using Bundler::Injector::inject, but then I need to bundle install. If I run that from within the task, the bundler has already initialized, so the require 'mongo' still fails. Should I do something to reload the bundler or is there actually a clean way to do this?
Add it to your Gemfile with :require => false:
gem "mongo", :require => false
This will allow bundler to install it and set up the load path, but it won't actually load the gem.
In your rake task, just require "mongo" to load it when you need it.

Ruby RSpec test for success or failure based on gem version being used

Is there a way to write an Rspec test to prove that some code fails if we are using a specific version of a gem and passes if we use another version of the same gem?
What I do currently is have one version in my Gemfile and then run rspec spec and see a test pass. Then I modify my Gemfile with the different gem version and bundle update and then run rspec spec again and see the same test fail.
I would like to have two tests, one that loads one version of the gem and tests for normal execution and succeeds and another test that loads a different version of the gem and tests for an exception and succeeds on the raised exception and both tests are run on the same rspec spec run. Is this even possible. If not, any suggestions on anything that does not involve me having to modify my Gemfile manually?
Also, in case it helps
I currently use bundler to install gems.
ruby 1.9.3p545
rspec 2.14.1
Also, I am not using Rails
I think you can specify the gem and version you want to use in the code:
it "does something" do
gem "gemname", "4.0"
require "gemname"
expect(subject).to do_something
end
But I don't know if what you're trying to do is a good idea because you should be testing with the same gems you would be using in production.
You could define a different environment to include the alternative version of your gem and use this while testing. For example, in your Gemfile
group :custom_test do
gem 'gemname', 'x.y.z'
end
And then run your tests as in
RAILS_ENV=custom_test rspec
I strongly suggest however that you look into solutions that let you test against different environments, gemfiles, rails and ruby versions (e.g. Jenkins or Travis etc.)

Resources