Rails: How to test code in the lib/ directory? - ruby-on-rails

I have a model which gets its data from a parser object. I'm thinking that the parser class should live in the lib/ directory (although I could be persuaded that it should live soewhere else). The question is: Where should my unit tests for the parser class be? And how do I ensure that they are run each time I run rake test?

In the Rails application I'm working on, I decided to just place the tests in the test\unit directory. I will also nest them by module/directory as well, for example:
lib/a.rb => test/unit/a_test.rb
lib/b/c.rb => test/unit/b/c_test.rb
For me, this was the path of last resistance, as these tests ran without having to make any other changes.

Here's one way:
Create lib/tasks/test_lib_dir.rake with the following
namespace :test do
desc "Test lib source"
Rake::TestTask.new(:lib) do |t|
t.libs << "test"
t.pattern = 'test/lib/**/*_test.rb'
t.verbose = true
end
end
Mimic the structure of your lib dir under the test dir, replacing lib code with corresponding tests.
Run rake test:lib to run your lib tests.
If you want all tests to run when you invoke rake test, you could add the following to your new rake file.
lib_task = Rake::Task["test:lib"]
test_task = Rake::Task[:test]
test_task.enhance { lib_task.invoke }

I was looking to do the same thing but with rspec & autospec and it took a little digging to figure out just where they were getting the list of directories / file patterns that dictated which test files to run. Ultimately I found this in lib/tasks/rspec.rake:86
[:models, :controllers, :views, :helpers, :lib, :integration].each do |sub|
desc "Run the code examples in spec/#{sub}"
Spec::Rake::SpecTask.new(sub => spec_prereq) do |t|
t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
end
end
I had placed my tests in a new spec/libs directory when the rpsec.rake file was configured to look in spec/lib. Simply renaming libs -> lib did the trick!

An easy and clean way is just to create a directory under test/unit/lib. Then create test as test/unit/lib/foo_test.rb corresponding to lib/foo.rb. No new rake tasks required, and you can nest more directories if needed to match the lib directory structure.

As of Rails 4.0:
rake test:all # Run all tests in any subdir of `test` without resetting the DB
rake test:all:db # Same as above and resets the DB
As of Rails 4.1, redefine test:run to include additional tasks when running rake or rake test:
# lib/tasks/test.rake
namespace :test do
Rake::Task["run"].clear
task run: ["test:units", "test:functionals", "test:generators", "test:integration", "test:tasks"]
["tasks"].each do |name|
Rails::TestTask.new(name => "test:prepare") do |t|
t.pattern = "test/#{name}/**/*_test.rb"
end
end
end
This has the added bonus of defining rake test:tasks in the given example.
As of Rails 4.2, test:run includes all subdirs of test including them when running rake test, and thus rake.

To not define additional rake tasks to run tests from the custom defined folders you may also run them with the command rake test:all. Tests folders structure for the lib folder or any other custom folder is up to you. But I prefer to duplicate them in classes: lib is matched to test/lib, app/form_objects to test/form_objects.

Use:
[spring] rake test:all
to run all tests, including the directories you created (like [root]/test/lib/).
Omit [spring] if tou aren't using it.

Related

rake task not running sub-tasks in order specified

In a rails 4.2 app, in Rakefile, I have this:
task(:default).clear
task :default => [:test, 'bundle:audit']
The output, always has bundle:audit running first. Why is that?
I read in some places that rake executes tasks as dependencies arise, but bundle:audit, as far as I can tell, does not depend on test. It is defined here:
https://github.com/rubysec/bundler-audit/blob/master/lib/bundler/audit/task.rb
To quote a comment discussing the same problem in Rake's GitHub repository:
It turns out that your problem is due to the way rails creates its test tasks:
desc "Run tests quickly by merging all types and not resetting db"
Rails::TestTask.new(:all) do |t|
t.pattern = "test/**/*_test.rb"
end
https://github.com/rails/rails/blob/v4.2.7.1/railties/lib/rails/test_unit/testing.rake#L24-L27
Here Rails uses Rails::TestTask for the test:all target which will load all test files.
def define
task #name do
if ENV['TESTOPTS']
ARGV.replace Shellwords.split ENV['TESTOPTS']
end
libs = #libs - $LOAD_PATH
$LOAD_PATH.unshift(*libs)
file_list.each { |fl|
FileList[fl].to_a.each { |f| require File.expand_path f }
}
end
end
https://github.com/rails/rails/blob/v4.2.7.1/railties/lib/rails/test_unit/sub_test_task.rb#L106-L118
But unlike Rake::TestTask, which immediately runs the tests, Rails::TestTask only requires the files necessary to run the tests then relies on the at_exit handler in Minitest to run the tests. This means rake dependencies are completely ignored for running tests.
I updated the links to the source code, because the discussion was about Rails 4.1.8, but the problem still exists the source code of Rails 4.2.7.1.
This problem was reported as an issue to the Rails team on GitHub and it was fixed in this PR.
That said: This problem should be fixed since Rails 5.0.0.

Ruby on Rails - run unit tests in subfolder

Is it possible to run tests only from one subfolder?
Something like this:
ruby -I"lib:test" test/functional/api/*
Thanks
I assume you're trying to find a way to run multiple unit tests in a specific directory and you're not using RSpec...
In that case, you can create a task in a Rakefile and run it from command line. This page Rake::TestTask will tell you how to create such a file. You're file is going to look something like this:
Rake::TestTask.new do |t|
t.libs << "test"
t.test_files = FileList['test/functional/api/*.rb']
t.verbose = true
end
And then run:
rake test
If you use rspec you can do this
rspec ./spec/models/
for a folder
and this
rspec ./spec/models/car_spec.rb
for one file
and this
rspec ./spec/models/car_spec.rb:34
for the test on line 34

How to use rake with rake tasks outside rails?

I think Rails is very heavy and I'm taking pieces out of my projects and making them standalone. My library of tasks, I would like it to work outside Rails. So there is no application and no config/application.rb, only the lib/ folder that defines tasks. How should I structure my rakefile to include all the tasks defined in lib/tasks/*rake? My non-working attempt is below.
#!/usr/bin/env/rake
d = Dir["#{File.dirname(__FILE__)}/src/tasks/*.rake" ]
d.each do |file|
require "tasks/"+ File.basename(file, File.extname(file))
end
The invocation is something like bundle exec rake -T -Isrc
Put this in your rake file
Dir["#{File.dirname(__FILE__)}/src/tasks/*.rake" ].each{ |rake_file| load rake_file }

rake:test not running custom tests in subdirectory

I'm using Rails 4.0.0.beta1. I added two directories: app/services and test/services.
I also added this code, based on reading testing.rake of railties:
namespace :test do
Rake::TestTask.new(services: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/services/**/*_test.rb'
end
end
I have found that rake test:services runs the tests in test/services; however, rake test does not run those tests. It looks like it should; here is the code:
Rake::TestTask.new(:all) do |t|
t.libs << "test"
t.pattern = "test/**/*_test.rb"
end
Did I overlook something?
Add a line like this after your test task definition:
Rake::Task[:test].enhance { Rake::Task["test:services"].invoke }
I don't know why they're not automatically getting picked up, but this is the only solution I've found that works for Test::Unit.
I think if you were to run rake test:all it would run your additional tests, but rake test alone won't without the snippet above.
For those using a more recent Rails version (4.1.0 in my case)
Use Rails::TestTask instead of Rake::TestTask and override run task:
namespace :test do
task :run => ['test:units', 'test:functionals', 'test:generators', 'test:integration', 'test:services']
Rails::TestTask.new(services: "test:prepare") do |t|
t.pattern = 'test/services/**/*_test.rb'
end
end
Jim's solution works, however it ends up running the extra test suite as a separate task and not as part of the whole (at least using Rails 4.1 it does). So test stats are run twice rather than aggregated. I don't feel this is the desired behaviour here.
This is how I ended up solving this (using Rails 4.1.1)
# Add additional test suite definitions to the default test task here
namespace :test do
Rails::TestTask.new(extras: "test:prepare") do |t|
t.pattern = 'test/extras/**/*_test.rb'
end
end
Rake::Task[:test].enhance ['test:extras']
This results in exactly expected behaviour by simply including the new test:extras task in the set of tasks executed by rake test and of course the default rake. You can use this approach to add any number of new test suites this way.
If you are using Rails 3 I believe just changing to Rake::TestTask will work for you.
Or simply run rake test:all
If you want to run all tests by default, override test task:
namespace :test do
task run: ['test:all']
end

How do I find the source file for a rake task?

I know you can view all possible rake tasks by typing
rake -T
But I need to know what exactly a task does. From the output, how can I find a source file that actually has the task? For example, I'm trying to find the source for the db:schema:dump task.
I know this is an old question, but in any case:
rake -W
This was introduced in rake 0.9.0.
http://rake.rubyforge.org/doc/release_notes/rake-0_9_0_rdoc.html
Support for the –where (-W) flag for showing where a task is defined.
Despite what others have said, you can programmatically get the source location of rake tasks in a rails application. To do this, just run something like the following in your code or from a console:
# load all the tasks associated with the rails app
Rails.application.load_tasks
# get the source locations of actions called by a task
task_name = 'db:schema:load' # fully scoped task name
Rake.application[task_name].actions.map(&:source_location)
This will return the source locations of any code that gets executed for this task. You can also use #prerequisites instead of #source_location to get a list of prerequisite task names (e.g. 'environment', etc).
You can also list all tasks loaded using:
Rake.application.tasks
UPDATE: See Magne's good answer below. For versions of rake >= 0.9.0 you can use rake -W to show the source location of your rake tasks.
There is no programmatic way to do this unfortunately. Rake tasks can be loaded either from rails itself, lib/tasks, or from any plugin with a tasks directory.
This should nab most everything not within Rails itself:
find . -name "*.rake" | xargs grep "whatever"
As for db:schema:dump, here's the source:
desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
task :dump => :environment do
require 'active_record/schema_dumper'
File.open(ENV['SCHEMA'] || "#{RAILS_ROOT}/db/schema.rb", "w") do |file|
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
end
end
It can be found on line 242 of lib/tasks/database.rake in the rails 2.2.2 gem. If you've got a different version of Rails, just search for "namespace :schema".
You probably actually want the source of the ActiveRecord::SchemaDumper, but I think you should have no trouble figuring out where that is. :-)
For most rake tasks in Rails, look in the Rails gem directory, in lib/tasks.
If you've vendored Rails into your app directory structure then look in vendor/rails/railties/lib/tasks instead
Either way, db:schema:dump is in databases.rake.

Resources