Minitest uninitialized constant error - ruby

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!

Related

Include module not working in gem

I have a gem called private_lib.
The file lib/private_lib.rb contains the following:
require 'private_lib/version'
require 'private_lib/handicap'
require 'private_lib/traversal_cap'
module PrivateLib
end
The lib/private_lib/handicap.rb file contains the following
# module for handicap functions
class Handicap
include TraversalCap
-- other code
end
and the file lib/private_lib/traversal_cap.rb contains the following
module TraversalCap
def some_method
end
-- other code
end
I also have a test file spec/handicap_spec.rb which contains the following
require "spec_helper"
describe Handicap do
include TraversalCap
-- some tests that access the ```Handicap``` class
-- some tests that access directly the traversal_cap some_method.
end
When I run rspec spec/handicap_spec, I get the following error
private_lib/lib/private_lib/handicap.rb:3:in `<class:Handicap>': uninitialized constant Handicap::TraversalCap (NameError)
from private_lib/lib/private_lib/handicap.rb:2:in `<top (required)>'
Why isn't the handicap class seeing the traversal_cap module?
It is because of the order you require the files.
At the time the line require 'private_lib/handicap' is run it reads the handicap.rb file and hits the line where you include TraversalCap. But you haven't yet run require 'private_lib/traversal_cap' at this point so the module is undefined.
Quick fix is to change the order of the require calls, or alternatively put require 'private_lib/traversal_cap' at the top of the handicap file.

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

Why does FakeFS break RSpec?

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

How to require file from `gem` which are not under `lib` directory?

I want to write spec for my rubocop custom cop. This gem has handy helpers defined here. I want to require it. How to achieve what?
I've tried to use Gem.find_files, and this gives me ability to require any file in that gem, but only under lib directory.
For example:
# this requires ...gems/rubocop-0.29.1/lib/rubocop/formatter/formatter_set.rb
require Gem.find_files('rubocop/formatter/formatter_set.rb').first
# but I need ...gems/rubocop-0.29.1/spec/support/cop_helper.rb
The following describes why I need it. I have spec/rubocop/my_custom_cop_spec.rb
require 'spec_helper'
require ? # What I should I write?
RSpec.describe RuboCop::Cop::Style::MyCustomCop do
it 'some test' do
inspect_source(cop, 'method(arg1, arg2)') # This helper I want to use from rubocop spec helpers
end
end
When I try plain require:
require 'rubocop/spec/support/cop_helper'
I receive error:
/home/user/.gem/ruby/2.0.0/gems/activesupport-4.2.0/lib/active_support/dependencies.rb:274
:in `require': cannot load such file -- rubocop/spec/support/cop_helper
I found a solution that I think is a little more syntactically elegant:
gem_dir = Gem::Specification.find_by_name("my_gem").gem_dir
require "#{gem_dir}/spec"
I was so blinded, I already have path to file and able to get relative from it.
require 'pathname'
rubocop_path = Pathname.new(Gem.find_files('rubocop.rb').first).dirname
rubocop_path # => ...gems/rubocop-0.29.1/lib
require "#{rubocop_path}/../spec/support/cop_helper.rb"

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

Resources