Why does Ruby run only some tests and not others? - ruby-on-rails

I'm using this command to run some tests...
bundle exec ruby -Itest test/functional/*.rb
In my test/functional dir I have two files...
file_sets_controller_test.rb
user_sessions_controller_test.rb
With the above command, the tests in file_sets_controller_test.rb all run but the ones in user_sessions_controller_test.rb don't run at all -- no errors or other output is reported.
However, I can run that file directly no problem, with this...
bundle exec ruby -Itest test/functional/user_sessions_controller_test.rb
That works fine.
I know that another option is to use rake test functionals, but that is extremely slow compared to running them directly.
ruby 1.9.3p327 (2012-11-10 revision 37606) [x86_64-darwin11.4.2]
Rails 3.2.12
Here's a part of my Gemfile...
group :development, :test do
gem 'ansi'
gem 'turn'
gem 'minitest'
gem 'minitest-matchers'
end
And here's my test_helper.rb...
ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'turn/autorun'
Turn.config.ansi = true
require 'minitest/autorun'
class ActiveSupport::TestCase
fixtures :all
end
Removing the Turn and Minitest gems doesn't change anything as far as I can tell.

The ruby command takes a ruby file to run as its first argument and makes additional arguments available to the ruby program. The shell is expanding your glob expression into 2 arguments and passing them to ruby, so ruby is running the first file name in the expansion.
Additional:
I think you can do what you want with something like...
bundle exec ruby -Itest -e "Dir.glob('test/functional/*_test.rb').each{|f| require File.expand_path(f)}"

Related

How to test a gem that depends on Rails and uses Rails commands

I'm making a gem that executes Rails commands (rails g model Item for example). When I use it in a Rails project, everything works. The problem is testing it in development outside of a Rails project.
I'm using cucumber with aruba to test if CLI commands execute the proper rails commands and generate the expected files. Unfortunately, when I try to test the behaviour it fails because there are no rails files and the commands require to be run inside of a Rails project in order to work.
I have added a rails dependency to the gemspec:
Gem::Specification.new do |spec|
spec.add_development_dependency 'rails', '~> 5.2.4'
end
I've thought about creating a new rails project on test start and then deleting it after the tests run, but that seems highly inconvenient. Is there a better way to do this?
A technique we use for WickedPDF is in the default rake task, before we run the tests, is to delete & generate a full Rails application in a gitignored subdirectory of the gem.
As a high-level simplified example of this Rakefile, it looks something like this:
Rakefile
require 'rake'
require 'rake/testtask'
# This gets run when you run `bin/rake` or `bundle exec rake` without specifying a task.
task :default => [:generate_dummy_rails_app, :test]
desc 'generate a rails app inside the test directory to get access to it'
task :generate_dummy_rails_app do
if File.exist?('test/dummy/config/environment.rb')
FileUtils.rm_r Dir.glob('test/dummy/')
end
system('rails new test/dummy --database=sqlite3')
system('touch test/dummy/db/schema.rb')
FileUtils.cp 'test/fixtures/database.yml', 'test/dummy/config/'
FileUtils.rm_r Dir.glob('test/dummy/test/*') # clobber existing tests
end
desc 'run tests in the test directory, which includes the generated rails app'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
Then, in test/test_helper.rb, we require the generated Rails app, which loads Rails itself and it's environment:
test/test_helper.rb
ENV['RAILS_ENV'] = 'test'
require File.expand_path('../dummy/config/environment.rb', __FILE__)
require 'test/unit' # or possibly rspec/minispec
# Tests can go here, or other test files can require this file to have the Rails environment available to them.
# Some tests may need to copy assets/fixtures/controllers into the dummy app before being run. That can happen here, or in your test setup.
You could skip parts of Rails that aren't needed by customizing the command that generates the app. For example, your gem may not need a database at all or a lot of things by default, so you command could be customized for a simpler app. Something like this maybe:
system("rails new test/dummy --skip-active-record \
--skip-active-storage --skip-action-cable --skip-webpack-install \
--skip-git --skip-sprockets --skip-javascript --skip-turbolinks")
In the WickedPDF project, we wanted to test across a wide range of "default" Rails installs, so we don't customize the command much, but that may generate much more than what you need to test some generator tasks.
WickedPDF also tests against multiple versions of Rails with TravisCI and multiple Gemfiles, but this could also be accomplished with the Appraisal gem that Luke suggested in this thread.
Check out Thoughbot's Appraisal gem:
Appraisal integrates with bundler and rake to test your library against different versions of dependencies in repeatable scenarios called "appraisals."
Here is a guide on how to set it up, including setting up a micro Rails app within your tests dir.

The gems of the files executed in a shell by Rails have to be in Gemfile

If I run a script from rails and that script requires a gem that is not found in Gemfile it does not work, however the script executed has nothing to do with Rails should behave the same as if you executed anything else like an ls for example
example: /tmp/fichero.rb
#! /usr/bin/env ruby
#encoding: utf-8
require "rubygems"
require 'choice'
require 'fileutils'
...
...
Gemfile
...
...
#gem 'choice'
...
...
controller:
stmt = "ruby /tmp/fichero.rb -p hola"
stdout, stderr, status = Open3.capture3(stmt)
or
stmt = "ruby /tmp/fichero.rb -p hola"
%x[#{stmt}]
both:
`require': cannot load such file -- choice (LoadError)
if I change Gemfile:
...
...
gem 'choice'
...
...
It works but I don't want this gem in my Gemfile
Thanks in advance
bundle exec - Shelling-out
Any Ruby code that opens a subshell (like system, backticks, or %x{}) will automatically use the current Bundler environment. If you need to shell out to a Ruby command that is not part of your current bundle, use the with_clean_env method with a block. Any subshells created inside the block will be given the environment present before Bundler was activated. For example, Homebrew commands run Ruby, but don't work inside a bundle:
Bundler.with_clean_env do
`brew install wget`
end

Load gems inside scripts run from the shell outside our Rails application directory?

We have a mail gem installed in our vendor/cache directory inside a Rails application.
The script is called "test" and is not inside the Rails application directory.
#! /usr/local/rvm/wrappers/ruby-1.9.3-p194/ruby
require 'date'
require 'fileutils'
require 'openssl'
require 'yaml'
require 'mail'
require 'dalli'
I get the following error when I execute this script from outside the Rails application.
/usr/local/rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- mail (LoadError)
from /usr/local/rvm/rubies/ruby-1.9.3-p194/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
I simply re-installed these gems (mail, dalli) in the standard Ruby path and it worked, but that's not ideal.
What do we need to so that these installed gems are found when we try to run this script outside of a Rails app? In other words, how do we specify the path to these gems?
Be sure that your gem are all declared in your Gemfile:
gem 'mail'
If you don't want them to be loaded by default, and load them only when needed, you can use the require statement that you are already using, and in your Gemfile add :require => false:
gem 'mail', :require => false
When you call your script from outside your Rails environment, and want to load the gems, prefix your script by bundle exec:
bundle exec my_script.rb
If you need to run your script from another location than your rails's app root, you must run:
BUNDLE_GEMFILE=/path/to/your/app/Gemfile bundle exec your_script
Keep in mind though that this may cause path issues if your script or your gems are looking for file in the path of your rails app

Cannot create Rails3 inside Rails2 in order to upgrade

I'm having a problem here. I'm trying to update my application from rails v2.3.11 to v3.0.20 and then move up from there. I've followed Ryan Bate's and other tutorials to do this however, when trying to create the rails3 app on top of the rails2 one, I get the following:
Tomas-MacBook-Pro:yfl_curr tomas$ rails new . --force
Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.
Type 'rails' for help.
Environment:
Tomas-MacBook-Pro:yfl_curr tomas$ ruby -v
ruby 1.9.2p320 (2012-04-20 revision 35421) [x86_64-darwin12.4.0]
Tomas-MacBook-Pro:yfl_curr tomas$ rails -v
Rails 3.0.20
I had to change the Rakefile and convert it to rails3 as it will not work if using v2:
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
require 'rake'
SampleApp::Application.load_tasks
Also boot.rb was changed to reflect this:
require 'rubygems'
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
I'm using bundler by the way. If I run the "rake rails:upgrade:check" it works fine.
What am I doing wrong?
Thanks guys for the help!!
Regards,
Tom

Ruby gems in stand-alone ruby scripts

This is a really basic ruby gems question. I'm familiar with writing simple ruby scripts like this:
#!/usr/bin/ruby
require 'time'
t = Time.at(123)
puts t
Now I'd like to use my own ruby gem in my script. In my rails project I can simply require 'my_gem'. However this doesn't work in a stand-alone script. What's the best/proper way to use my own gem in a stand-alone ruby script?
You should be able to simply require it directly in recent versions of Ruby.
# optional, also allows you to specify version
gem 'chronic', '~>0.6'
# just require and use it
require 'chronic'
puts Chronic::VERSION # yields "0.6.7" for me
If you are still on Ruby 1.8 (which does not require RubyGems by default), you will have to explicitly put this line above your attempt to load the gem:
require 'rubygems'
Alternatively, you can invoke the Ruby interpreter with the flag -rubygems which will have the same effect.
See also:
http://docs.rubygems.org/read/chapter/3#page70
http://docs.rubygems.org/read/chapter/4
You could use something like this. It will install the gem if it's not already installed:
def load_gem(name, version=nil)
# needed if your ruby version is less than 1.9
require 'rubygems'
begin
gem name, version
rescue LoadError
version = "--version '#{version}'" unless version.nil?
system("gem install #{name} #{version}")
Gem.clear_paths
retry
end
require name
end
load_gem 'your_gem'
It is to be noted that bundler itself can deal with this. It's particularly interesting since bundler ships with Ruby by default since version 2.6, and you don't need to install it manually anymore.
The idea is:
to require bundler/inline at the top of your script,
to use the gemfile method, and declare the gems you need inside a block, like you'd do in a Gemfile,
after the end of this section, your gems are available!
For instance:
require 'bundler/inline'
gemfile do
source 'https://rubygems.org'
gem 'rainbow'
end
# From here on, rainbow is available so I can
# print colored text into my terminal
require 'rainbow'
puts Rainbow('This will be printed in red').red
The official documentation can be found on bundler website: bundler in a single file ruby script
Installing gems with something like the following should work. Be mindful of whether gems should be installed as part of system ruby or a user's.
#!/usr/bin/env ruby
require 'rubygems'
def install_gem(name, version=Gem::Requirement.default)
begin
gem name, version
rescue LoadError
print "ruby gem '#{name}' not found, " <<
"would you like to install it (y/N)? : "
answer = gets
if answer[0].downcase.include? "y"
Gem.install name, version
else
exit(1)
end
end
end
# any of the following will work...
install_gem 'activesupport'
install_gem 'activesupport', '= 4.2.5'
install_gem 'activesupport', '~> 4.2.5'
# require as normal (since not all gems install & require with same name) ...
require 'active_support/all'
...
I'm not sure if I understood your question right, but perhaps you don't have a gem, even if you write it (you are a beginner, so perhaps you misunderstood the concept of gems).
Just to be sure: You have a gemspec for your gem? If not, then you have no gem, but a single script.
When you want your own script inside another script, you may just do:
require 'my_script'
With ruby 1.8 this works fine, if my_script.rb is in the same folder as your main script. With ruby 1.9+ you can use:
require_relative 'my_script'
There is no need of a gem in this case.

Resources