Running rspec from within ruby multiple times within the same process - ruby

I am creating a test automation tool that runs a rspec test from within ruby, not from command line.
I run my test like this that runs and gives me a output hash with pass / fail etc.
config = RSpec.configuration
json_formatter = RSpec::Core::Formatters::JsonFormatter.new(config.out)
reporter = RSpec::Core::Reporter.new(json_formatter)
config.instance_variable_set(:#reporter, reporter)
RSpec::Core::Runner.run(["#{Rails.root}/spec/test1_spec.rb"])
puts json_formatter.output_hash
All is great until i run it again and i get the error
> undefined method `visit' for #<RSpec::Core::ExampleGroup::Nested_7:0x007ff3d343d978>
how do i reload / make sure all spec_helper and files are loaded before i run it again ?
thanks
Rick

Add
require 'spec_helper'
to the top of each spec file.

I had the same problems, turns out it can be fixed with one line of code only:
require 'capybara'
include Capybara::DSL # Add this line right after requiring capybara
Source: http://codedecoder.wordpress.com/2013/01/10/undefined-method-visit-for-rspec-capybara/

I had a similar issue and had to do a RSpec#reset between runs to make sure everything was cleaned up.
http://www.rubydoc.info/github/rspec/rspec-core/RSpec#reset-class_method

Related

change cucumber runtime options

Is there any way to programmatically change options for the runtime object which is used for cucumber feature execution?
In Ruby + Cucumber: How to execute cucumber in code? it is described how to run tests from ruby script, but in addition to that I need to change some runtime options like profile, etc.
Looking at the source code a can see that there is a runtime.configure method, but I do not know which option to pass in to change anything.
Any help regarding this issue is much appreciated!
Create a Rake file like the one below and pass your options
require 'rubygems'
require 'cucumber'
require 'cucumber/rake/task'
Cucumber::Rake::Task.new :features do |t|
t.cucumber_opts = "*.feature -f json -o cucumber.json"
end

Why RSpec runs specs twice when running from within ruby and spec file is reloaded?

I'm trying to use RSpec from within existing ruby runtime and run specs every time when file changes. This is because of JRuby and JVM startup time. To eliminate this on every run I'd like to start ruby once, then only reload changed files and run specs. I was using guard (with diffrent extensions) and watchr but all seem to suffer from an issue described below.
I nailed the issue down to RSpec itself. The problem is, when running RSpec via RSpec::Core::Runner.run several times it works fine until spec file is reloaded using load. Then RSpecs starts running specs twice.
I've created sample project showing this issue live: https://github.com/mostr/rspec_double_run_issue
Below is sample output:
ruby run_spec_in_loop.rb
Running spec from within ruby runtime
.
Finished in 0.00047 seconds
1 example, 0 failures
loading spec file via 'load' as if it was changed and we wanted changes to be picked up
Running spec from within ruby runtime
..
Finished in 0.001 seconds
2 examples, 0 failures
Is there any way to tell RSpec to clear its context between subsequent runs when run from within existing ruby runtime? I've also raised this as an issue #826 for RSpec Core project.
Summarizing the answer here in order to remove this question from the "Unanswered" filter...
Per RJHunter's observation, the explanation has been documented on the GitHub RSpec Core project here:
https://github.com/rspec/rspec-core/issues/826#issuecomment-15089030
For posterity (in case the above link dies), here are the details:
The RSpec runner is already calling load internally, your second load is what's causing the double run issue.
I quickly knocked up a script based off your example which reruns a single spec file, changes the specs to something else, then reruns them, work's correctly without the second load
See: https://gist.github.com/JonRowe/5192007
The aforementioned Gist contains:
require 'rspec'
spec_file = 'spec/sample_spec.rb'
File.open(spec_file, 'w') { |file| file.write 'describe { specify { expect(true).to eq false } }' }
1.upto(5) do |i|
puts "Running spec from within ruby runtime"
::RSpec::Core::Runner.run([spec_file], STDERR, STDOUT)
#rewriting the spec file
File.open(spec_file, 'w') { |file| file.write "describe { specify { expect(#{i}).to eq false } }" }
end

Can RubyMine IDE recognize rspec tests if filename does not have _spec suffix?

Let me preface this by saying I am a newbie to Ruby.
I am doing an extremely basic tutorial on Ruby in RubyMine, and as part of the tutorial, we create a class in a .rb Ruby file called thing.rb. In addition to the class, the tutorial has us put an Rspec test in the same .rb file. The .rb file looks like the following:
require 'rspec'
class Thing
def value
5
end
end
describe Thing do
it "should have a value of 6" do
Thing.new.value.should eq(7)
end
end
If I right-click the project folder and "Run all specs in the project", I get errors and messages including "0 files found" and "Empty test suite." If I just run the rb script, I get no errors...the script runs fine.
The STRANGE thing is that if I add a second file to the project called thing_spec.rb and put in it only the test from above:
require 'rspec'
require_relative 'thing'
describe Thing do
it "should have a value of 6" do
Thing.new.value.should eq(7)
end
end
And then right-click the project and select "Run all specs," the tests run fine. Notice I said the tests (plural)...RubyMine will run the test in thing.rb AND the test in thing_spec.rb.
Why won't it recognize the test in thing.rb without my having to add a second file called thing_spec.rb?? This makes no sense to me. Is there anyway I could have it run the rspec tests from within thing.rb without having to create a second file?
In case it is important: I work on a Mac, have RubyMine version 4.5, using ruby interpreter 1.9.3, rspec 2.12.0.
If you go in Run > Edit Configurations...
And select All Specs in <Your Project> you'll see Filename Mask: **/*_spec.rb
This means when you tell RubyMine to run "All Specs", it only runs files which match the regex.
Now when you add second file and you do require_relative to load the other one, so both the tests run.

Mocha Mock Carries To Another Test

I have been following the 15 TDD steps to create a Rails application guide - but have run into an issue I cannot seem to resolve. For the functional test of the WordsController, I have the following code:
class WordsControllerTest < ActionController::TestCase
test "should get learn" do
get 'learn'
assert_response :success
end
test "learn passes a random word" do
some_word = Word.new
Word.expects(:random).returns(some_word)
get 'learn'
assert_equal some_word, assigns('word')
end
end
In the Word class I have the following code:
class Word < ActiveRecord::Base
def self.random
all = Word.find :all
all[rand(all.size)]
end
end
When I run the tests, I experience the following error (shortened for brevity):
1) Failure: unexpected invocation: Word(...).random() satisfied expectations:
- expected exactly once, already invoked once: Word(...).random()
I have tried changing changing the order of the tests along with a multitude of other things, but time and time again I continue to receive the same test failure - that Word.random() has already been invoked.
I'm running Rails 3.0 beta 4 and Mocha 0.9.8. I've searched long and hard for a solution to my problem, but I can't seem to find it. I'm new to Ruby/Rails so am rather unfamiliar with the language and the frameworks.
Thanks in advance!
mocha needs to be loaded last. I struggled a lot with this problem too.
#Gemfile
group :test
gem 'mocha', '~>0.9.8', :require => false
...
end
and
test_helper.rb
....
#at the very bottom
require 'mocha'
I had the same problem, mocked functionality was not isolated to a test, it seems to be a problem with the load order of Mocha.
I had some issues getting Mocha to work with Rails3. I found a few stackoverflow posts regarding, but didn't stumble across the solution until I found a post on agoragames.com
Basically, in the Gemfile of your project, the require for Mocha should look like:
gem 'mocha', :require => false
Then in test/test_helper.rb, add a require line for mocha:
...
...
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'mocha'
class ActiveSupport::TestCase
...
...
I think the require line for mocha in the Gemfile means that you need to already have mocha installed as a gem, bundler won't take care of it for you.
How are you requiring mocha? Are you using bundler? It sounds a bit as if the mocha teardown hook isn't being called?
Additionally, it seems mocha_teardown is not being called with rails31. Mocks that are setup are never removed... (this additional hack fixes it)
class ActiveSupport::TestCase
def teardown
super
Mocha::Mockery.instance.teardown
Mocha::Mockery.reset_instance
end
end
Those solutions didn't work for me on their own, using Ruby 2.2.2, Rails 4.2.2, mocha 1.1.0, shoulda-context 1.2.1, factory_girl_rails 4.5.0 and a few more testing related gems.
What did it was also moving these two lines at the bottom of my test_helper.rb:
require 'mocha/setup'
require 'mocha/test_unit'
I also removed require 'test/unit'. It appears that mocha/test_unit already does that for me.

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