When I want to run all model tests we do
rails test:models
If I similarly would like to run tests that sits in a folder called service_objects (in the test folder) - what would be the required steps?
With inspiration from multiple, sources I have tried the following in lib/tasks:
namespace :test do
Rails::TestTask.new(classes: 'test:prepare') do |t|
t.pattern = 'test/service_objects/**/*_test.rb'
end
end
But running rails test:service_objects returns this error message:
NameError: uninitialized constant Rails::TestTask
Replace Rails::TestTask with Rails::TestUnit::Runner as shown in the file below, with the require path indicated at the top.
Then to run ONLY the tests in test/focused directory, you can call
rails test:focused
and to run ALL tests in the test directory EXCEPT those in test/long_running, you can call
rails test:without_long_running
Tested with Rails 5.1.6
The new Rails 5 test runner does have some really helpful features, but sometimes you still need a little more control.
# lib/tasks/test_tasks.rake
require "rails/test_unit/runner"
namespace :test do
task :focused => "test:prepare" do
$: << "test"
test_files = FileList['test/focused/*_test.rb']
Rails::TestUnit::Runner.run(test_files)
end
task :without_long_running_tests => "test:prepare" do
$: << "test"
test_files = FileList['test/**/*_test.rb'].exclude('test/long_running/**/*_test.rb')
Rails::TestUnit::Runner.run(test_files)
end
end
Credit should go to jonatack may 2015 post here: https://github.com/rails/rails/issues/19997
Related
I have a TDD solution written in Ruby 1.9.3 (latest stable Windows RubyInstaller).
The application is in the app directory and in the sibling test directory I have 4 files containing tests.
I have a Rakefile executing a MiniTest test suite that merely includes the test case files.
require 'rake/testtask'
Rake::TestTask.new do |t|
t.libs << "test"
t.test_files = FileList['test/ts_*.rb']
t.verbose = true
end
ts_test_suite.rb:
gem 'minitest'
require_relative 'tc_requirement_tests.rb'
require_relative 'tc_command_tests.rb'
require_relative 'tc_movement_tests.rb'
require_relative 'tc_placement_tests.rb'
When I execute rake test from the commandline 2 of the 4 files execute successfully and (for some strange reason) the other two are not being executed. tc_requirement_tests.rb is one of those two files:
require 'test_base.rb'
require './app/turn_to.rb'
require './app/direction.rb'
class RequirementTests < TestBase
def requirement_test_1
#bad_robot.place(0, 0, Direction::NORTH)
#bad_robot.move
assert_equal "Output: 0,1,NORTH", #bad_robot.report_posture
end
def requirement_test_2
#bad_robot.place(0, 0, Direction::NORTH)
#bad_robot.turn(TurnTo::LEFT)
assert_equal "Output: 0,0,WEST", #bad_robot.report_posture
end
def requirement_test_3
#bad_robot.place(1, 2, Direction::EAST)
#bad_robot.move
#bad_robot.move
#bad_robot.turn(TurnTo::LEFT)
#bad_robot.move
assert_equal "Output: 3,3,NORTH", #bad_robot.report_posture
end
end
If I deliberately put a syntax error in one of the two test case files that are not executing, Rake complains with the expected error message, so I know that it is "seeing" the file.
Any ideas why 2 of the 4 test case files are not being executed?
It sounds like your test framework needs the test function names to begin test_. Try renaming your test functions so that they're in the format test_requirement_1, test_requirement_2, etc.
I found a blog post about Testing Factories First (by BigBinary - which happens to be a Minitest/spec version of Thoughtbot's RSpec original).
Could you please show me the equivalent without the spec framework - just with Minitest (Rails)?
The Thoughtbot approach (RSpec)
spec/factories_spec.rb
FactoryGirl.factories.map(&:name).each do |factory_name|
describe "The #{factory_name} factory" do
it 'is valid' do
build(factory_name).should be_valid
end
end
end
Rakefile
if defined?(RSpec)
desc 'Run factory specs.'
RSpec::Core::RakeTask.new(:factory_specs) do |t|
t.pattern = './spec/factories_spec.rb'
end
end
task spec: :factory_specs
The BigBinary approach (Minitest, spec)
spec/factories_spec.rb
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
describe FactoryGirl do
EXCEPTIONS = %w(base_address base_batch bad_shipping_address)
FactoryGirl.factories.each do |factory|
next if EXCEPTIONS.include?(factory.name.to_s)
describe "The #{factory.name} factory" do
it 'is valid' do
instance = build(factory.name)
instance.must_be :valid?
end
end
end
end
lib/tasks/factory.rake
desc 'Run factory specs.'
Rake::TestTask.new(:factory_specs) do |t|
t.pattern = './spec/factories_spec.rb'
end
task test: :factory_specs
What is the Minitest equivalent (without spec)?
The approach I am presenting below is slightly different than the two original solutions - in the sense that my approach creates only one test, within which I cycle through the factories and run an assertion against each. I was not able to create a solution that mimics the original solutions any closer - which is (I believe) a separate test method for each factory. If someone could show such an implementation, that would be cool.
test/aaa_factories_tests/factories_test.rb
require File.expand_path(File.dirname(__FILE__) + '/../test_helper.rb')
class FactoriesTest < Minitest::Unit::TestCase
puts "\n*** Factories Test ***\n\n"
EXCEPTIONS = %w(name_of_a_factory_to_skip another_one_to_skip)
def test_factories
FactoryGirl.factories.each do |factory|
next if EXCEPTIONS.include?(factory.name.to_s)
instance = FactoryGirl.build(factory.name)
assert instance.valid?, "invalid factory: #{factory.name}, error messages: #{instance.errors.messages.inspect}"
instance = factory = nil
end
end
end
Thanks to the way Minitest works out of the box -- add any directories under test/ and minitest-rails will automatically create the associated rake task for it. So let's say you add a test/api/ directory, rake minitest:api will automagically be available. -- I see the task when I run bundle exec rake -T with no other configurations:
rake minitest:aaa_factories_tests # Runs tests under test/aaa_factories_tests
And I am able to run this task successfully:
-bash> bundle exec rake minitest:aaa_factories_tests
*** Factories Test ***
Run options: --seed 19208
# Running tests:
.
Finished tests in 0.312244s, 3.2026 tests/s, 9.6079 assertions/s.
1 tests, 3 assertions, 0 failures, 0 errors, 0 skips
Despite the ugliness of prepending the directory with aaa, I am able to have the factories tested first with:
bundle exec rake minitest:all
The reason for the aaa prepend solution is MiniTest does a Dir glob and on Mac OS X (and other Unix variants) the results are sorted alphabetically (though the results differ across different platforms).
As well, I prepended the default_tasks array with aaa_factories_tests to have the factories tested first in the default Minitest task (i.e. when running bundle exec rake minitest).
lib/tasks/factories_first.rake
MiniTest::Rails::Testing.default_tasks.unshift('aaa_factories_tests') if Rails.env =~ /^(development|test)\z/
Note that the above condition avoids erroneously referencing Minitest in environments where it is unavailable (I have confined minitest-rails to :test and :development groups in Gemfile). Without this if-condition, pushing to Heroku (for example to staging or production) will result in uninitialized constant MiniTest.
Of course I am also able to run the factories test directly:
bundle exec ruby -I test test/aaa_factories_tests/factories_test.rb
Here is a solution for MiniTest without the spec framework:
test/factories_test.rb
require File.expand_path(File.dirname(__FILE__) + '/test_helper')
class FactoriesTest < ActiveSupport::TestCase
EXCEPTIONS = %w(griddler_email)
FactoryBot.factories.map(&:name).each do |factory_name|
next if factory_name.to_s.in?(EXCEPTIONS)
context "The #{factory_name} factory" do
should 'be valid' do
factory = build(factory_name)
assert_equal true, factory.valid?, factory.errors.full_messages
end
end
end
end
lib/tasks/factory.rake
namespace :test do
desc 'Test factories'
Rake::TestTask.new(:factories) do |t|
t.pattern = './test/factories_test.rb'
end
end
task minitest: 'test:factories'
The most important thing is to use taks minitest instead of task test if you want the factories tests to be run before other tests.
I use Ruby 2 and Rails 4. I have a folder test/lib, where a few tests are located.
But running rake test does not use them. Only the other tests (models, controllers, ...) are running.
Where do I have to add the lib folder?
I already tried MiniTest::Rails::Testing.default_tasks << 'lib', but I get NameError Exception: uninitialized constant MiniTest::Rails. I did not add the minitest gem to my Gemfile, because Ruby 2 uses it by default.
To use MiniTest::Rails::Testing.default_tasks << 'lib' you need to add the minitest-rails gem to your Gemfile. It is separate from Minitest and adds enables many Minitest features missing that are not enabled in Rails by default. And minitest-rails adds other features, such as creating rake tasks for all the directories that have tests. So without any changes to your Rakefile you can run things like this:
$ rake minitest:lib
Alternatively, to do this the old fashioned way, you can add the following to your Rakefile:
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
Rake::Task[:test].enhance { Rake::Task["test:lib"].invoke }
This assumes you want to run your lib tests without using any database fixtures. If you want the fixtures and database transactions, then you should create the rake task with a dependency on "test:prepare".
namespace :test do
desc "Test lib source"
Rake::TestTask.new(:lib => "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/lib/**/*_test.rb'
t.verbose = true
end
end
Rake::Task[:test].enhance { Rake::Task["test:lib"].invoke }
I have a bunch of tests that aren't unit or functional tests, they're of the format test/foo/special_test.rb
I want to create a rake task like rake test:units that will run all the tests in the foo folder. How do I do this?
Edit: I'd actually like rake test:foo to be a little different from rake test:units, in that I do not want it to run when I do simply rake test.
I don't remember where this is from, so unfortunately I can't give proper acknowledgement, but this should work. I say "should" because I've stopped using it, but grabbed it from my git history.
# First, 'reopen' the default :test namespace and create your custom task.
namespace :test do
Rake::TestTask.new(:foo_tests => ["test:prepare", "other_dependent_rake_tasks"] ) do |t|
DatabaseCleaner.strategy = :transaction # If using this.
t.libs << "test"
# Will also get subfolders within test/foo
t.test_files = FileList['test/foo/**/*_test.rb', 'test/foo/*_test.rb']
end
end
You can remove the default "test" task and redefine it so that when you run rake test it will automatically also run rake test:foo_tests.
remove_task "test"
desc 'Adding onto Rails regular tests'
task :test do
# Add all the names of tests you want run here.
errors = %w(test:units test:functionals test:integration test:foo_tests).collect do |task|
begin
puts "Running: #{task}"
Rake::Task[task].invoke
nil
rescue => e
task
end
end.compact
abort "Errors running #{errors * ', '}!" if errors.any?
end
I wrote a little monkeypatch to the Rails MySQLAdapter and want to package it up to use it in my other projects. I am trying to write some tests for it but I am still new to testing and I am not sure how to test this. Can someone help get me started?
Here is the code I want to test:
unless RAILS_ENV == 'production'
module ActiveRecord
module ConnectionAdapters
class MysqlAdapter < AbstractAdapter
def select_with_explain(sql, name = nil)
explanation = execute_with_disable_logging('EXPLAIN ' + sql)
e = explanation.all_hashes.first
exp = e.collect{|k,v| " | #{k}: #{v} "}.join
log(exp, 'Explain')
select_without_explain(sql, name)
end
def execute_with_disable_logging(sql, name = nil) #:nodoc:
#Run a query without logging
#connection.query(sql)
rescue ActiveRecord::StatementInvalid => exception
if exception.message.split(":").first =~ /Packets out of order/
raise ActiveRecord::StatementInvalid, "'Packets out of order' error was received from the database. Please update your mysql bindings (gem install mysql) and read http://dev.mysql.com/doc/mysql/en/password-hashing.html for more information. If you're on Windows, use the Instant Rails installer to get the updated mysql bindings."
else
raise
end
end
alias_method_chain :select, :explain
end
end
end
end
Thanks.
General testing
You could start reading about testing.
After you are understanding the basics of testing, you should think what you have changed. Then make some tests which test for
the original situation, resulting in errors since you updated it. So reverse the test after it indeed is working for the original situation.
the new situation to see whether you have implemented your idea correctly
The hardest part is to be sure that you covered all situations. Finally, if both parts pass then you could say that your code it working as expected.
Testing gems
In order to test gems you can run
rake test:plugins
to test all plugins of your rails application (see more in chapter 6 of the testing guide), this only works when the gem is in the vendor directory of an application.
Another possibility is to modify the Rakefile of the gem by including a testing task. For example this
desc 'Test my custom made gem.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end
would run all available tests in the test directory ending with _test.rb. To execute this test you can type rake test (from the gem directory!).
In order to run the tests for the gem by default (when typing just rake) you can add/modify this line:
task :default => :test
I used the second method in my ruby-bbcode gem, so you could take a look at it to see the complete example.