Why does FakeFS break RSpec? - ruby

test_spec.rb: (from FakeFS example)
require 'fakefs/spec_helpers'
describe 'Test' do
include FakeFS::SpecHelpers
it 'should fail' do
expect(1).to eq(2)
end
end
describe 'Test2' do
it 'should fail' do
expect(1).to eq(2)
end
end
rspec spec/test_spec.rb returns superclass mismatch for class File for the first test and normal expected: 2 got: 1 in the second case. Matcher changing (e.g. be_kind_of(String)) does not affect the result. Why does this happen, and how can it be fixed?
ruby -v
ruby 2.4.0dev (2016-03-19 trunk 54188) [x86_64-linux]

I just had this issue, and the accepted answer did not help me.
But I did eventually solve the issue by adding the following line to the top of my spec_helper.rb:
require 'pp'
I have a .rspec file with the following line to ensure spec_helper is loaded always:
--require spec_helper
It is documented in the FakeFS readme that you need to require pp before fakefs in order to avoid this problem, but I did not require pp myself. It must have been required implicitly by some other gem I use*.
Thus by explicitly requiring pp before fakefs, my specs now run as they should.
* I suspect RSpec uses pp for pretty printing error messages, as I could cause the exception in the line expect(true).to eq false

Thanks #d.g for link to fakefs issue. Things that works:
Gemfile
gem 'fakefs', require: 'fakefs/safe'
spec/spec_helper.rb
require 'fakefs/spec_helpers'
RSpec.configure do |config|
config.include FakeFS::SpecHelpers, fakefs: true
end
test_spec.rb
require_relative 'spec_helper.rb'
describe 'Test', fakefs: true do
it 'should fail' do
expect(1).to be_kind_of(String)
end
end

Related

All SauceLabs tests run with Capybara result in "Unnamed Ruby job" and no metadata

I'm setting up a standalone RSpec/Capybara test suite integrated with SauceLabs, but the instructions in the documentation don't seem to be working for me.
Here are the relevant parts of my spec_helper.rb:
require 'capybara'
require 'capybara/rspec'
require 'sauce/capybara'
Sauce.config do |config|
config[:browsers] = [
[ "OSX 10.10", "Safari", "8" ]
]
end
Capybara.default_driver = :sauce
And here's the feature (not_found_spec.rb):
feature 'Enroll: 404', :sauce => true do
before :each do
#nonexistent_curriculum = FactoryGirl.build :curriculum
#enroll = Enroll.new
end
context 'When I visit a page that does not exist' do
scenario 'I see a Not Found message' do
#enroll.go #nonexistent_curriculum
expect(#enroll.not_found).to be_visible
end
end
end
When I then run rspec, the specs run and pass, but no metadata of any kind is recorded. All I see on SauceLabs is "Unnamed Ruby job".
What am I missing?
When you run
bundle exec rake sauce:install:spec
it creates a sauce_helper.rb which is then typically required from the end of your rails_helper.rb or spec_helper.rb depending on what *_helper.rb files you have. It looks like you copied the Sauce config part from sauce_helper into your spec_helper but you haven't shown that you have
require "sauce"
in there which is in the generated sauce_helper. Without requiring "sauce" it may be that sauce/rspec/rspec.rb is not getting required which is where all the hooks into rspec for tests with sauce: true are set up.

Minitest uninitialized constant error

I am trying to run Minitest with Spec syntax with rake test and get this error:
/path/to/gem/spec/script_spec.rb:3:in `<top (required)>': uninitialized constant MyGem (NameError)
My Rakefile:
require 'rake/testtask'
Rake::TestTask.new do |t|
t.test_files = FileList['spec/*_spec.rb']
end
My file structure:
gem/
--lib/
----script.rb
--spec/
----script_spec.rb
--Rakefile
My script.rb:
module MyGem
class OptionParser
def self.option?(arg)
arg =~ /^-{1,2}\w+$/
end
end
end
Using Minitest::Spec syntax in script_spec.rb:
require "minitest/autorun"
describe MyGem::OptionParser do
describe "option?" do
it "must be true for option name" do
OptionParser.option?('--nocolor').assert true
end
end
end
How do I fix it? Maybe lib folder isn't loaded? Do I miss something related to Spec syntax?
MyGem::OptionParser is not loaded in your tests. You either need to require it in your spec file or create a spec_helper where you require all files that you need in all your tests so you only need to require 'spec_helper' in your specs.
Also, since you're using the spec syntax, you will have to `require 'minitest/spec'. Your spec_helper would look something like:
# spec/spec_helper.rb
require 'minitest/spec'
require 'minitest/autorun'
require 'script'
And do this to your Rakefile so you can do require 'script' like above in your specs instead of doing require_relative '../lib/script'.
require 'rake/testtask'
Rake::TestTask.new do |t|
t.test_files = FileList['spec/*_spec.rb']
end
Lastly, for your spec to work, add require 'spec_helper' at the top of your script_spec file. You'll have to do this for all your spec files and make sure to add require for all the files you need to load in your specs to your spec_helper file.
Since you're also doing spec-style testing, you might want to change your test to this:
MyGem::OptionParser.option?('--nocolor').must_equal true
You could also have code like this in your 'spec_helper' file to automatically load all files in your lib folder:
Dir["../lib/**/*.rb"].each do |rb_file|
require rb_file
end
Hope this helps!

Sinatra-Contrib: undefined method `namespace'

I'm new to TDD, and I'm trying to write methods to generate URLs on a per-class basis that inherit from a parent class using Sinatra and the Namespace library in Sinatra-Contrib. I'm not too far along, because I've gotten a failed RSpec test that has kept me from moving further: undefined method 'namespace'. Can anyone help?
Gemfile:
source 'https://rubygems.org'
ruby '1.9.3'
gem 'sinatra'
gem 'sinatra-contrib'
gem 'rack'
gem 'thin'
group :development, :test do
gem 'rspec'
gem 'rack-test'
gem 'ZenTest'
gem 'autotest-growl'
gem 'autotest-fsevent'
end
base_model.rb:
require 'sinatra'
require 'sinatra/namespace'
require 'rack'
def generate_routes_for_model(model_class, rootUrl)
namespace rootUrl do
get '/show' do
"I'm the model's show route"
end
end
end
base_model_spec.rb
require_relative '../base_model.rb'
require 'rack/test'
set :environment, :test
class Foo
end
def app
Sinatra::Application
end
include Rack::Test::Methods
describe 'Create Routes for test Class' do
it "should load foo.show" do
generate_routes_for_model(Foo, '/foo')
get '/foo/show'
last_response.should be_ok
end
end
Here's the result of the test:
Failures:
1) Create Routes for test Class should load foo.show
Failure/Error: generate_routes_for_model(Foo, '/foo')
NoMethodError:
undefined method `namespace' for #<RSpec::Core::ExampleGroup::Nested_2:0x007f8571102e00>
# ./base_model.rb:16:in `generate_routes_for_model'
# ./spec/base_model_spec.rb:24:in `block (2 levels) in <top (required)>'
It appears to be a scope problem, on first look. namespace is a class method of a Sinatra extension (which is why you call it within the class definition and not inside an instance method).
When you run RSpec, is namespace ever within a class that inherits from Sinatra::Base? I don't think so. You need to provide a Sinatra class that namespace can run within. e.g.
class Foo; end
app = Sinatra.new do
register Sinatra::Namespace
end
def generate_routes_for_model(app_class, model_class, rootUrl)
['show'].each do |route|
app_class.namespace rootUrl do
get route do
"I'm the model's show route"
end
end
end
end
generate_routes_for_model app, Foo, "/"
app.run!
Then going to http://localhost:4567/show will respond with "I'm the model's show route".
Or perhaps use class_eval to define the code, there's a few ways you could tackle this, main thing to keep in mind is make sure the scope is right or the app or RSpec etc won't be able to find the method.
Edit:
Also, I'd move the generation into a before block, as it's set up for an integration test (you're essentially saying "If the route exists then the generation worked, I don't need to test the method here", so it's a black box test of the public API - an integration test by any other name:) If you wanted to test the method itself that would be a unit test, and you'd need to look into the app to see the routes had been generated.
describe 'Create Routes for test Class' do
before do
generate_routes_for_model(Foo, '/foo')
get '/foo/show' # this, too, is not a test but a pre-requisite for the test
end
it "should load foo.show" do
last_response.should be_ok
end
end

How to use RSpec to test a Sinatra application within a gem?

I am writing a gem which includes a Sinatra application that a developer can extend. For example:
# gem code:
require 'sinatra'
module Mygem
class Application < Sinatra::Base
get 'auth/login' {}
get 'auth/logout {}
end
end
# developer code:
require 'mygem'
class DeveloperApp < Mygem::Application
# ..
end
I am also getting started using RSpec. How should I configure RSpec for testing this functionality?
The references above are all informative and useful but mostly rails specific. I found it quite hard to find a simple recipe for a basic test of a modular Sinatra app, so I am hoping this will answer the question for others. Here is a completely bare-bones, small as possible test. This is probably not the only way to do it, but it works well for a modular app:
require 'sinatra'
class Foo < Sinatra::Base
get '/' do
"Hello"
end
end
require 'rack/test'
describe Foo do
include Rack::Test::Methods
def app
Foo.new
end
it "should be testable" do
get '/'
last_response.should be_ok
end
end
Note that there is no need to have the server running when you launch the test (some tutorials I saw implied that you do) - it's not an integration test.
It's actually pretty simple -- just add rspec to your gemfile (then bundle install), and make a directory in your gem called spec/. Once you've done that, add a file spec/spec_helper.rb that contains some configuration for rspec (mostly requiring various files from your library) as well as defining some helper methods for your specs. Then, for each model and controller, make a file called my_model_name_spec.rb or my_controller_name_spec.rb, and do the test there.
Here are some useful resources for getting started with rspec:
Railscasts:
http://railscasts.com/episodes/275-how-i-test
http://railscasts.com/episodes/71-testing-controllers-with-rspec
http://railscasts.com/episodes/157-rspec-matchers-macros/
And for some more advanced (but well-explained) stuff:
http://benscheirman.com/2011/05/dry-up-your-rspec-files-with-subject-let-blocks
Be sure to include the rack-test gem.
You spec helper should have:
require 'rack/test'
require 'foo' # or where ever your app is
# This can go in a helper somewhere
module AppHelper
def app
Foo.new
end
end
RSpec.configure do |config|
config.include Rack::Test::Methods
config.include AppHelper
end
Then, your spec can be as follows:
require 'spec_helper'
# Example app. Delete this example.
class Foo < Sinatra::Base
get '/' do
'Jesse Pinkman'
end
end
describe Foo do
it 'is testable' do
get '/' do
expect(last_response).to be_ok
end
end
end

How to stub any instances for a given class using Rspec Mocks

The following code raises an error: undefined method 'any_instance' for String:Class
require 'rspec'
RSpec.configure do |config|
config.mock_with :rspec
end
describe String do
it 'stubs' do
String.any_instance.stub(:foo).and_return(1)
''.foo.should eq(1)
end
end
How can I include the Mocks module into the Class or Object class?
any_instance was recently added to rspec, so your example now works for me as it is with rspec 2.7.
Update for rspec 3:
The new way to do this is
allow_any_instance_of(String).to receive(:foo).and_return(1)
Here is more any_instance documentation: https://relishapp.com/rspec/rspec-mocks/docs/working-with-legacy-code/any-instance
With RSpec Mocks in versions previous to 2.6.0, you cannot do it. However you can use any_instance with Mocha(as seen here) or in later versions of Rspec.
In your spec/spec_helper.rb
Make sure you have this line:
config.mock_with :mocha
uncommented.

Resources