Running RSpec Files From ruby code - ruby

I'm trying to run RSpec tests straight from ruby code. More specifically, I'm running some mysql scripts, loading the rails test environment and then I want to run my rspec tests (which is what I'm having trouble with)... I'm trying to do this with a rake task. Here is my code so far:
require "spec/autorun"
require"spec"
require "spec/rake/spectask"
RAILS_ENV = 'test'
namespace :run_all_tests do
desc "Run all of your tests"
puts "Reseting test database..."
system "mysql --user=root --password=dev < C:\\Brian\\Work\\Personal\\BrianSite\\database\\BrianSite_test_CreateScript.sql"
puts "Filling database tables with test data..."
system "mysql --user=root --password=dev < C:\\Brian\\Work\\Personal\\BrianSite\\database\\Fill_Test_Tables.sql"
puts "Starting rails test environment..."
task :run => :environment do
puts "RAILS_ENV is #{RAILS_ENV}"
# Run rspec test files here...
require "spec/models/blog_spec.rb"
end
end
I thought the require "spec/models/blog_spec.rb" would do it, but the tests aren't running. Anyone know where I'm going wrong?
UPDATE: I've added the require "spec/autorun" command at the top of the file and now I am running into this error when I do a rake run_all_tests:run :
C:/Ruby/lib/ruby/gems/1.8/gems/rspec-1.3.0/lib/spec/runner/options.rb:283:in fi
les_to_load': File or directory not found: run_all_tests:run (RuntimeError)
from C:/Ruby/lib/ruby/gems/1.8/gems/rspec-1.3.0/lib/spec/runner/options.
rb:275:ineach'
from C:/Ruby/lib/ruby/gems/1.8/gems/rspec-1.3.0/lib/spec/runner/options.
rb:275:in files_to_load'
from C:/Ruby/lib/ruby/gems/1.8/gems/rspec-1.3.0/lib/spec/runner/options.
rb:133:inrun_examples'
from C:/Ruby/lib/ruby/gems/1.8/gems/rspec-1.3.0/lib/spec/runner.rb:61:in
run'
from C:/Ruby/lib/ruby/gems/1.8/gems/rspec-1.3.0/lib/spec/runner.rb:45:in
autorun'
from C:/Ruby/bin/rake:19
It's hitting this error when it gets to the require "spec/models/blog_spec.rb" line. This file does exist because when I try and change the require statement, I just get a file not found error. It seems like rspec is trying to now run the tests, but is running into problems... any thoughts?
Thanks for any help.

Try adding require "spec/autorun to the top of your file.
You don't need to do it that way though, because there are built in Rake tasks (that's what the spec/rake/spectask is including) to do what you're doing: http://rspec.info/documentation/tools/rake.html

Related

how to invoke bundler commands from within a Serverspec/RSpec test

I have a project to create a template ruby project.
I am using serverspec and want to verify the behaviour of the template.
However, using command(`rake -T`) fails. If I execute the command manually, it works as expected.
Debugging, when the test is running in Serverspec, it finds the wrong Gemfile - it is using the Gemfile from my project (.), not the generated directory (target/sample_project).
How can I invoke rake or bundler commands withing a Serverspec/Rspec test?
sample code:
require "spec_helper"
require 'serverspec'
require 'fileutils'
set :backend, :exec
set :login_shell, true
describe "Generated Template" do
output_dir='target'
project_dir="#{output_dir}/sample_project"
# Hooks omitted to create the sample_project
# and change working directory to `project_dir`
describe command('rake -T') do
its(:stdout) { should include "rake serverspec:localhost" }
its(:stdout) { should include "rake serverspec:my_app" }
end
end
Bundler has provision for running external shell commands documented here: http://bundler.io/v1.3/man/bundle-exec.1.html
Running bundler/rake tasks is possible using rspec using Bundler.with_clean_env, instead of Serverspec.
require 'bundler'
require 'rspec'
RSpec.describe "Generated Template" do
output_dir='target'
project_dir="#{output_dir}/sample_project"
around(:example) do |example|
#Change context, so we are in the generated project directory
orig_dir=Dir.pwd
Dir.chdir(project_dir)
example.run
Dir.chdir(orig_dir)
end
around(:example) do |example|
Bundler.with_clean_env do
example.run
end
end
it "should include localhost" do
expect(`rake -T 2>&1`).to include "rake serverspec:localhost"
end
end

Capistrano Deploy, access ActiveRecord

Okay,
I'm sorry if the title is not descriptive enough, but allow me to explain what I want to achieve:
I have a Rails 3 application
During my deploy, it needs to call pg_dump with the correct parameters to restore a backup
The task needs to be ran after the deploy is done but before the migrations.
The problem I have however, is that for this task, I would like to access Rails specific code, which is not working as Capistrano keeps throwing a lot of errors at me like gems not available or module not defined.
This is my Rake task:
namespace :deploy do
namespace :rm do
desc 'Backup the database'
task :backup do
# Generates the command to invoke the Rails runner
# Used by the cfg method to execute the ActiveRecord configuration in the rails config.
def runner
dir = "#{fetch(:deploy_to)}/current"
bundler = "#{SSHKit.config.command_map.prefix[:bundle].first} bundle exec"
env = fetch(:rails_env)
"cd #{dir}; #{bundler} rails r -e #{env}"
end
def cfg(name)
env = fetch(:rails_env)
command = "\"puts ActiveRecord::Base.configurations['#{env}']['#{name}']\""
"#{runner} #{command}"
end
on roles(:db) do
timestamp = Time.now.strftime('%Y%m%d%H%M%S')
backups = File.expand_path(File.join(fetch(:deploy_to), '..', 'backups'))
execute :mkdir, '-p', backups
dump = "PGPASSWORD=`#{cfg('password')}` pg_dump -h `#{cfg'host')}` -U `#{cfg('username')}` `#{cfg('database')}`"
fn = "#{timestamp}_#{fetch(:stage)}.sql.gz"
path = File.join(backups, fn)
execute "#{dump} | gzip > #{path}"
end
end
end
end
In it's current form, it simply generates a string with the runner method and dumps that inside the cfg method.
I tried rewriting the runner method, but for some reason I keep getting the runner --help output from the remote server, but the command being generated in the output is correct, and works locally just fine.
We are using Ruby 2.2.2 and RVM on the remote server.
Is it even possible to do what we are trying to construct together?
I'd suggest writing a rake task inside your Rails app and invoking that from your Capistrano task. This is how the Capistrano rails tasks work.
within release_path do
with rails_env: fetch(:rails_env) do
execute :rake, "db:migrate"
end
end

rake aborted after tests run & (intentionally) fail, before error messages are printed

I am running through the TestFirst tutorial and can't get past the first challenge due to some troubles with Rake (and rspec in general).
The tests I am trying to run:
require 'hello'
describe "the hello function" do
it "says hello" do
hello.should == "Hello!"
end
end
describe "the greet function" do
it "says hello to someone" do
greet("Alice").should == "Hello, Alice!"
end
it "says hello to someone else" do
greet("Bob").should == "Hello, Bob!"
end
end
I've only gotten so far as to create the hello.rb file (according to the tutorial) and adding
def hello
end
For the record, before I created the file, I got the long output saying that the require "hello" wasn't working, as expected, and upon creating the file that went away. So that all worked fine.
When I run the rake command, my output is (the bolded part is my main concern):
wendy#wendy-EL1352:~/the_odin_project/learn_ruby/00_hello$ rake
(in /home/wendy/the_odin_project/learn_ruby)
the hello function
says hello (FAILED - 1)
Failures:
1) the hello function says hello
Failure/Error: hello.should == "Hello!"
expected: "Hello!"
got: nil (using ==)
# ./00_hello/hello_spec.rb:120:in `block (2 levels) in '
Deprecation Warnings:
Using should from rspec-expectations' old :should syntax without explicitly enabling >the syntax is deprecated. Use the new :expect syntax or explicitly enable :should >instead. Called from /home/wendy/the_odin_project/learn_ruby/00_hello/hello_spec.rb:120:in >`block (2 levels) in '.
If you need more of the backtrace for any of these deprecations to
identify where to make the necessary changes, you can configure
config.raise_errors_for_deprecations!, and it will turn the
deprecation warnings into errors, giving you the full backtrace.
1 deprecation warning total
Finished in 0.00334 seconds (files took 0.14558 seconds to load)
1 example, 1 failure
Failed examples:
rspec ./00_hello/hello_spec.rb:119 # the hello function says hello
rake aborted!
/home/wendy/.rvm/rubies/ruby-2.0.0-p481/bin/ruby -S rspec /home/wendy/the_odin_project/learn_ruby/00_hello/hello_spec.rb -I/home/wendy/the_odin_project/learn_ruby/00_hello -I/home/wendy/the_odin_project/learn_ruby/00_hello/solution -f documentation -r ./rspec_config failed
/home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-2.13.1/lib/rspec/core/rake_task.rb:156:in run_task'
/home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-2.13.1/lib/rspec/core/rake_task.rb:124:inblock (2 levels) in initialize'
/home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-2.13.1/lib/rspec/core/rake_task.rb:122:in `block in initialize'
Tasks: TOP => default => spec
(See full trace by running task with --trace)
I'm not hugely concerned with the deprecation warning (I've looked through enough to be reasonably certain these aren't related). Although if you think that's the cause I'll bow my head in shame. I do need to figure out how to either rewrite the specs or change the config settings, but I have faith that I can do that myself. My real concern here is that Rake has access to the tests and can run them, but aborts before showing the error messages.
If I run rspec hello_spec.rb the output is here:
wendy#wendy-EL1352:~/the_odin_project/learn_ruby/00_hello$ rspec hello_spec.rb
/home/wendy/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in require': cannot load such file -- hello (LoadError)
from /home/wendy/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:inrequire'
from /home/wendy/the_odin_project/learn_ruby/00_hello/hello_spec.rb:116:in <top (required)>'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-3.0.2/lib/rspec/core/configuration.rb:1057:inload'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-3.0.2/lib/rspec/core/configuration.rb:1057:in block in load_spec_files'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-3.0.2/lib/rspec/core/configuration.rb:1057:ineach'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-3.0.2/lib/rspec/core/configuration.rb:1057:in load_spec_files'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-3.0.2/lib/rspec/core/runner.rb:97:insetup'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-3.0.2/lib/rspec/core/runner.rb:85:in run'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-3.0.2/lib/rspec/core/runner.rb:70:inrun'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-3.0.2/lib/rspec/core/runner.rb:38:in invoke'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/gems/rspec-core-3.0.2/exe/rspec:4:in'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/bin/rspec:23:in load'
from /home/wendy/.rvm/gems/ruby-2.0.0-p481#railstutorial_rails_4_0/bin/rspec:23:in'
So I'm kind of wondering why running rake has no problem linking the required hello.rb file but the rspec command doesn't. I just want to get these tests to run (and fail) properly so I can get on with the task.
The rakefile:
# This Rakefile has all the right settings to run the tests inside each lab
gem 'rspec', '~>2'
require 'rspec/core/rake_task'
task :default => :spec
desc "run tests for this lab"
RSpec::Core::RakeTask.new do |task|
lab = Rake.application.original_dir
task.pattern = "#{lab}/*_spec.rb"
task.rspec_opts = [ "-I#{lab}", "-I#{lab}/solution", '-f documentation', '-r ./rspec_config']
task.verbose = false
end
Adding gem 'ruby gems' does nothing but add more confusion to the outputs.
I have initialized rspec with rspec --init in previous attempts at this, both in the 00_hello directory as well as in the learn_ruby directory. In this case, I run into exactly the same error messages.
I've been going at learning Ruby and Rails for the past few months. Once or twice I've almost asked a question here, but I've ended up finding my answer halfway through drafting it. I am not having that kind of luck this time. I am truly stumped. Please help.
Thank you.
Edit with more info on rspec --init and use of 'spec_helper'
in the 00_hello folder, rspec --init and then including the spec_helper in the hello_spec.rb (as shown above - I included require 'spec_helper' below the require 'hello') produces the following error when run with the rake command:
wendy#wendy-EL1352:~/the_odin_project/learn_ruby/00_hello$ rake (in
/home/wendy/the_odin_project/learn_ruby)
/home/wendy/.rvm/rubies/ruby-2.0.0-p481/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in
`require': cannot load such file -- spec_helper (LoadError)
In the learn_ruby directory, I get the same output as above, where the tests run well enough to fail, but then I see rake abort! before the errors are listed and the same error as before:
the hello function says hello (FAILED - 1)
Failures:
1) the hello function says hello
Failure/Error: hello.should == "Hello!"
NameError:
undefined local variable or method hello' for #<RSpec::ExampleGroups::TheHelloFunction:0x00000002989278>
# ./00_hello/hello_spec.rb:122:inblock (2 levels) in '
Finished in 0.00094 seconds (files took 0.16985 seconds to load) 1
example, 1 failure
Failed examples:
rspec ./00_hello/hello_spec.rb:121 # the hello function says hello
rake aborted! /home/wendy/.rvm/rubies/ruby-2.0.0-p481/bin/ruby -S
rspec /home/wendy/the_odin_project/learn_ruby/00_hello/hello_spec.rb
-I/home/wendy/the_odin_project/learn_ruby/00_hello -I/home/wendy/the_odin_project/learn_ruby/00_hello/solution -f documentation -r ./rspec_config failed
(the reason the test failure is different is because I've gone back to just having the hello.rb file created without inserting the class name into the file - the tests are half running, but the rake aborted! won't go away)
This guy:
-I/home/wendy/the_odin_project/learn_ruby/00_hello/solution -f documentation -r ./rspec_config failed
can be found in the Rakefile:
RSpec::Core::RakeTask.new do |task|
lab = Rake.application.original_dir
task.pattern = "#{lab}/*_spec.rb"
**task.rspec_opts = [ "-I#{lab}", "-I#{lab}/solution", '-f documentation', '-r ./rspec_config']**
task.verbose = false
end
But I do not have enough understanding of Rake to even parse apart Google search results for problems with that line, or find what search terms to use to find relevant information. :/

How to integrate rubocop with Rake?

rubocop is a code style checker for Ruby. A similar tool to rubocop, Cane, can be integrated with Rake. I prefer rubocop to Cane since rubocop makes checks based on the Ruby Style Guide and it seems to spot more problems. To automate the process of style checking I would like to integrate rubocop with Rake so that the build fails if code quality is lacking.
Gem already supports adding tests to packages via Rake. I would like to do the same with style checks so that style checks are run along with the tests. How can I do this?
If it helps to start with a Rakefile here is one:
# -*- coding: utf-8; mode: ruby -*-
require 'bundler/gem_tasks'
require 'rake/testtask'
Rake::TestTask.new do |t|
t.libs << 'test'
t.test_files = FileList['test/unit/test*.rb']
end
desc 'Run tests'
task default: :test
As of version 0.10.0 rubocop contain a custom rake task that you can use. Just put the following in your Rakefile
require 'rubocop/rake_task'
RuboCop::RakeTask.new
Make sure to use upper-case 'R' and 'C' or you will get a NameError.
I highly recommend,
require 'rubocop/rake_task'
RuboCop::RakeTask.new(:rubocop) do |t|
t.options = ['--display-cop-names']
end
This uses the rubocop's own rake tasks and allows you to pass options if you like.
You will probably find https://github.com/yujinakayama/guard-rubocop useful if you use Guard for your RSpec tests. It enables Rubocop to give you instant feedback as soon as you save the file, along with your test results.
I needed to do something similar myself, and ended up looking in the internal source code of the RuboCop::RakeTask here:
https://github.com/rubocop/rubocop/blob/a34a1c2c2dd1fa6d90ffd06c183421a495a0717c/lib/rubocop/rake_task.rb#L40-L43
require 'rubocop'
cli = CLI.new
puts 'Running RuboCop...' if verbose
result = cli.run(options)
abort('RuboCop failed!') if result.nonzero? && fail_on_error
You can actually invoke similar code directly in your own codebase / rake task.
I ended up writing a little wrapper module I can call to, with some default flags that I always want to be applied:
module RubocopCli
def self.run!(*args)
require "rubocop"
cli = RuboCop::CLI.new
result = cli.run(["--display-cop-names", "--force-exclusion", "--fail-level", "autocorrect", *args])
raise "RubocopCli.run! Linting failed." if result.nonzero?
end
end
Then you can call it with additional args from any task, or app code, like:
files_to_lint = %w[lib/whatever.rb spec/lib/whatever_spec.rb]
RubocopCli.run!("--auto-correct", *files_to_lint)
You can shell out via Rake with the options you prefer:
desc 'Run Rubocop with options'
task rubocop: :environment do
sh 'bundle exec rubocop -D --format offenses --format progress || true'
end
I then recommend modifying the default task to include the output. The trick is to clear the task and then add back what you want. Note the need to end with || true so that an error from Rubocop will not prevent the next task from running. Here's what I do, which also uses parallel tests:
task(:default).clear.enhance ['parallel:parallel_prepare', 'parallel:spec',
'parallel:features', 'lint:rubocop',
'lint:rails_best_practices']
I would recommend shelling out to the rubocop program. It's the simplest solution. Just add this to your Rakefile:
task test: :rubocop
task :rubocop do
sh 'rubocop'
end

Testing a rake task in rspec (and cucumber)

I'm new to Ruby, and I've been trying to learn Rake, RSpec, and Cucumber. I found some code that will help me test my Rake tasks, but I'm having trouble getting it to work. I was told here: http://blog.codahale.com/2007/12/20/rake-vs-rspec-fight/ to drop this:
def describe_rake_task(task_name, filename, &block)
require "rake"
describe "Rake task #{task_name}" do
attr_reader :task
before(:all) do
#rake = Rake::Application.new
Rake.application = #rake
load filename
#task = Rake::Task[task_name]
end
after(:all) do
Rake.application = nil
end
def invoke!
for action in task.instance_eval { #actions }
instance_eval(&action)
end
end
instance_eval(&block)
end
end
into my spec_helper.rb file.
I've managed to take this code out and run it in my cucumber steps like this:
When /^I run the update_installers task$/ do
#rake = Rake::Application.new
Rake.application = #rake
load "lib/tasks/rakefile.rb"
#task = Rake::Task["update_installers"]
for action in #task.instance_eval { #actions }
instance_eval(&action)
end
instance_eval(&block)
Rake.application = nil
end
but when I try to get things working in rspec, I get the following error.
ArgumentError in 'Rake task
install_grapevine should install to
the mygrapevine directory'
wrong number of arguments (1 for 2)
/spec/spec_helper.rb: 21:in instance_eval'
/spec/spec_helper.rb: 21:inblock in invoke!'
/spec/spec_helper.rb: 20:in each'
/spec/spec_helper.rb: 20:ininvoke!'
/spec/tasks/rakefile_spec.rb:12:in `block (2 levels) in
'
Unfortunately, I've got just under a week of ruby under by belt, so the metaprogramming stuff is over my head. Could anyone point me in the right direction?
This works for me: (Rails3/ Ruby 1.9.2)
When /^the system does it's automated tasks$/ do
require "rake"
#rake = Rake::Application.new
Rake.application = #rake
Rake.application.rake_require "tasks/cron"
Rake::Task.define_task(:environment)
#rake['cron'].invoke
end
Substitute your rake task name here and also note that your require may be "lib/tasks/cron" if you don't have the lib folder in your load path.
I agree that you should only do minimal work in the Rake task and push the rest to models for ease of testing. That being said I think it's important to ensure that the code is ACTUALLY run in my cron tasks during my integration tests so I think very mild testing of the rake tasks is justified.
Since testing rake is just too much for me, I tend to move this problem around. Whenever I find myself with a long rake task that I want to test, I create a module/class in lib/ and move all the code from the task there. This leaves the task to a single line of Ruby code, that delegates to something more testable (class, module, you name it). The only thing that remains untested is whether the rake task invokes the right line of code (and passes the right parameters), but I think that is OK.
It might be useful to tell us which is the 21nd line of your spec_helper.rb. But given that the approach you posted digs deep in rake (referring to its instance variables), I would entirely abandon it for what I suggested in the previous paragraph.
I've just spent a little while getting cucumber to run a rake task so I thought I'd share my approach. Note: This is using Ruby 2.0.0 and Rake 10.0.4, but I don't think the behaviour has changed since previous versions.
There are two parts to this. The first is easy: with a properly set up instance of Rake::Application then we can access tasks on it by calling #[] (eg rake['data:import']). Once we have a task we can run it by calling #invoke and passing in the arguments (eg rake['data:import'].invoke('path/to/my/file.csv').
The second part is more awkward: properly setting up an instance of Rake::Application to work with. Once we've done require 'rake' we have access to the Rake module. It already has an application instance, available from Rake.application, but it's not yet set up — it doesn't know about any of our rake tasks. It does, however, know where to find our Rakefile, assuming we've used one of the standard file names: rakefile, Rakefile, rakefile.rb or Rakefile.rb.
To load the rakefile we just need to call #load_rakefile on the application, but before we can do that we need to call #handle_options. The call to #handle_options populates options.rakelib with a default value. If options.rakelib is not set then the #load_rakefile method will blow up, as it expects options.rakelib to be enumerable.
Here's the helper I've ended up with:
module RakeHelper
def run_rake_task(task_name, *args)
rake_application[task_name].invoke(*args)
end
def rake_application
require 'rake'
#rake_application ||= Rake.application.tap do |app|
app.handle_options
app.load_rakefile
end
end
end
World(RakeHelper)
Pop that code into a file in features/support/ and then just use run_rake_task in your steps, eg:
When /^I import data from a CSV$/ do
run_rake_task 'data:import', 'path/to/my/file.csv'
end
The behavior might have changed since the correct answer was posted. I was experiencing problems executing two scenarios that needed to run the same rake task (only one was being executed despite me using .execute instead of .invoke). I thought to share my approach to solve the issue (Rails 4.2.5 and Ruby 2.3.0).
I tagged all the scenarios that require rake with #rake and I defined a hook to setup rake only once.
# hooks.rb
Before('#rake') do |scenario|
unless $rake
require 'rake'
Rake.application.rake_require "tasks/daily_digest"
# and require other tasks
Rake::Task.define_task(:environment)
$rake = Rake::Task
end
end
(Using a global variable is suggested here: https://github.com/cucumber/cucumber/wiki/Hooks#running-a-before-hook-only-once)
In the step definition I simply called $rake
# step definition
Then(/^the daily digest task is run$/) do
$rake['collector:daily_digest'].execute
end
Any feedback is welcome.

Resources