From b4df25366a3c8f133f8329bc35f1d53926704b5a Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist and Chris Toomey Date: Fri, 25 Jan 2013 13:44:36 -0500 Subject: Add `rails test` command to run the test suite To run the whole test suite: $ rails test To run the test file(s): $ rails test test/unit/foo_test.rb [test/unit/bar_test.rb ...] To run the test suite $ rails test [models,helpers,units,controllers,mailers,...] For more information, see `rails test --help`. This command will eventually replacing `rake test:*`, and `rake test` command will actually invoking `rails test` instead. --- railties/CHANGELOG.md | 21 +++ railties/lib/rails/commands.rb | 15 +++ railties/lib/rails/commands/test_runner.rb | 92 +++++++++++++ railties/test/application/test_runner_test.rb | 183 ++++++++++++++++++++++++++ 4 files changed, 311 insertions(+) create mode 100644 railties/lib/rails/commands/test_runner.rb create mode 100644 railties/test/application/test_runner_test.rb (limited to 'railties') diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 420ed476b2..6bf9b22a2d 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -19,6 +19,27 @@ *Terence Lee* +* Add `rails test` command to run the test suite + + To run the whole test suite: + + $ rails test + + To run the test file(s): + + $ rails test test/unit/foo_test.rb [test/unit/bar_test.rb ...] + + To run the test suite + + $ rails test [models,helpers,units,controllers,mailers,...] + + For more information, see `rails test --help`. + + This command will eventually replacing `rake test:*`, and `rake test` + command will actually invoking `rails test` instead. + + *Prem Sichanugrist and Chris Toomey* + * Add notice message for destroy action in scaffold generator. *Rahul P. Chaudhari* diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index aacde52cfc..c76af7d01f 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -5,6 +5,7 @@ aliases = { "d" => "destroy", "c" => "console", "s" => "server", + "t" => "test", "db" => "dbconsole", "r" => "runner" } @@ -16,6 +17,7 @@ The most common rails commands are: generate Generate new code (short-cut alias: "g") console Start the Rails console (short-cut alias: "c") server Start the Rails server (short-cut alias: "s") + test Running the test file (short-cut alias: "t") dbconsole Start a console for the database specified in config/database.yml (short-cut alias: "db") new Create a new Rails application. "rails new my_app" creates a @@ -78,6 +80,19 @@ when 'server' server.start end +when 'test' + $LOAD_PATH.unshift("./test") + require 'rails/commands/test_runner' + if ["-h", "--help"].include?(ARGV.first) + Rails::TestRunner.help_message + exit + else + require APP_PATH + Rails.application.require_environment! + Rails.application.load_tasks + Rails::TestRunner.start(ARGV) + end + when 'dbconsole' require 'rails/commands/dbconsole' Rails::DBConsole.start diff --git a/railties/lib/rails/commands/test_runner.rb b/railties/lib/rails/commands/test_runner.rb new file mode 100644 index 0000000000..a65b508505 --- /dev/null +++ b/railties/lib/rails/commands/test_runner.rb @@ -0,0 +1,92 @@ +require 'optparse' +require 'minitest/unit' + +module Rails + # Handling the all the logic behind +rails test+ command. + class TestRunner + class << self + # Parse the test suite name from the arguments array and pass in a list + # of file to a new +TestRunner+ object, then invoke the evaluation. If + # the argument is not a test suite name, it will be treated as a file + # name and passed to the +TestRunner+ instance right away. + def start(arguments) + case arguments.first + when nil + new(Dir['test/**/*_test.rb']).run + when 'models' + new(Dir['test/models/**/*_test.rb']).run + when 'helpers' + new(Dir['test/helpers/**/*_test.rb']).run + when 'units' + new(Dir['test/{models,helpers,unit}/**/*_test.rb']).run + when 'controllers' + new(Dir['test/controllers/**/*_test.rb']).run + when 'mailers' + new(Dir['test/mailers/**/*_test.rb']).run + when 'functionals' + new(Dir['test/{controllers,mailers,functional}/**/*_test.rb']).run + when 'integration' + new(Dir['test/integration/**/*_test.rb']).run + else + new(arguments).run + end + end + + # Print out the help message which listed all of the test suite names. + def help_message + puts "Usage: rails test [path to test file(s) or test suite type]" + puts "" + puts "Run single test file, or a test suite, under Rails'" + puts "environment. If the file name(s) or suit name is omitted," + puts "Rails will run all the test suites." + puts "" + puts "Support types of test suites:" + puts "-------------------------------------------------------------" + puts "* models (test/models/**/*)" + puts "* helpers (test/helpers/**/*)" + puts "* units (test/{models,helpers,unit}/**/*" + puts "* controllers (test/controllers/**/*)" + puts "* mailers (test/mailers/**/*)" + puts "* functionals (test/{controllers,mailers,functional}/**/*)" + puts "* integration (test/integration/**/*)" + puts "-------------------------------------------------------------" + end + end + + # Create a new +TestRunner+ object with a list of test file paths. + def initialize(files) + @files = files + Rake::Task['test:prepare'].invoke + MiniTest::Unit.output = SilentUntilSyncStream.new(MiniTest::Unit.output) + end + + # Run the test files by evaluate each of them. + def run + @files.each { |filename| load(filename) } + end + + # A null stream object which ignores everything until +sync+ has been set + # to true. This is only to be used to silence unnecessary output from + # MiniTest, as MiniTest calls +output.sync = true+ right before output the + # first test result. + class SilentUntilSyncStream < File + # Create a +SilentUntilSyncStream+ object by given a stream object that + # this stream should set +MiniTest::Unit.output+ to after +sync+ has been + # set to true. + def initialize(target_stream) + @target_stream = target_stream + super(File::NULL, 'w') + end + + # Swap +MiniTest::Unit.output+ to another stream when +sync+ is true. + def sync=(sync) + if sync + @target_stream.sync = true + MiniTest::Unit.output = @target_stream + end + + super + end + end + end +end diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb new file mode 100644 index 0000000000..49bce508ee --- /dev/null +++ b/railties/test/application/test_runner_test.rb @@ -0,0 +1,183 @@ +require 'isolation/abstract_unit' + +module ApplicationTests + class TestRunnerTest < ActiveSupport::TestCase + include ActiveSupport::Testing::Isolation + + def setup + build_app + create_schema + end + + def teardown + teardown_app + end + + def test_should_not_display_heading + create_test_file + run_test_command.tap do |output| + assert_no_match /Run options:/, output + assert_no_match /Running tests:/, output + end + end + + def test_run_shortcut + create_test_file :models, 'foo' + output = Dir.chdir(app_path) { `bundle exec rails t test/models/foo_test.rb` } + assert_match /1 tests, 1 assertions, 0 failures/, output + end + + def test_run_single_file + create_test_file :models, 'foo' + assert_match /1 tests, 1 assertions, 0 failures/, run_test_command("test/models/foo_test.rb") + end + + def test_run_multiple_files + create_test_file :models, 'foo' + create_test_file :models, 'bar' + assert_match /2 tests, 2 assertions, 0 failures/, run_test_command("test/models/foo_test.rb test/models/bar_test.rb") + end + + def test_run_file_with_syntax_error + app_file 'test/models/error_test.rb', <<-RUBY + require 'test_helper' + def; end + RUBY + + error_stream = Tempfile.new('error') + redirect_stderr(error_stream) { run_test_command('test/models/error_test.rb') } + assert_match /SyntaxError/, error_stream.read + end + + def test_invoke_rake_test_prepare + app_file "lib/tasks/test.rake", <<-RUBY + namespace :test do + task :prepare do + puts "Hello World" + end + end + RUBY + create_test_file + assert_match /Hello World/, run_test_command + end + + def test_run_models + create_test_file :models, 'foo' + create_test_file :models, 'bar' + create_test_file :controllers, 'foobar_controller' + run_test_command("models").tap do |output| + assert_match /FooTest/, output + assert_match /BarTest/, output + assert_match /2 tests, 2 assertions, 0 failures/, output + end + end + + def test_run_helpers + create_test_file :helpers, 'foo_helper' + create_test_file :helpers, 'bar_helper' + create_test_file :controllers, 'foobar_controller' + run_test_command('helpers').tap do |output| + assert_match /FooHelperTest/, output + assert_match /BarHelperTest/, output + assert_match /2 tests, 2 assertions, 0 failures/, output + end + end + + def test_run_units + create_test_file :models, 'foo' + create_test_file :helpers, 'bar_helper' + create_test_file :unit, 'baz_unit' + create_test_file :controllers, 'foobar_controller' + run_test_command('units').tap do |output| + assert_match /FooTest/, output + assert_match /BarHelperTest/, output + assert_match /BazUnitTest/, output + assert_match /3 tests, 3 assertions, 0 failures/, output + end + end + + def test_run_controllers + create_test_file :controllers, 'foo_controller' + create_test_file :controllers, 'bar_controller' + create_test_file :models, 'foo' + run_test_command('controllers').tap do |output| + assert_match /FooControllerTest/, output + assert_match /BarControllerTest/, output + assert_match /2 tests, 2 assertions, 0 failures/, output + end + end + + def test_run_mailers + create_test_file :mailers, 'foo_mailer' + create_test_file :mailers, 'bar_mailer' + create_test_file :models, 'foo' + run_test_command('mailers').tap do |output| + assert_match /FooMailerTest/, output + assert_match /BarMailerTest/, output + assert_match /2 tests, 2 assertions, 0 failures/, output + end + end + + def test_run_functionals + create_test_file :mailers, 'foo_mailer' + create_test_file :controllers, 'bar_controller' + create_test_file :functional, 'baz_functional' + create_test_file :models, 'foo' + run_test_command('functionals').tap do |output| + assert_match /FooMailerTest/, output + assert_match /BarControllerTest/, output + assert_match /BazFunctionalTest/, output + assert_match /3 tests, 3 assertions, 0 failures/, output + end + end + + def test_run_integration + create_test_file :integration, 'foo_integration' + create_test_file :models, 'foo' + run_test_command('integration').tap do |output| + assert_match /FooIntegration/, output + assert_match /1 tests, 1 assertions, 0 failures/, output + end + end + + def test_run_whole_suite + types = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration] + types.each { |type| create_test_file type, "foo_#{type}" } + run_test_command('') .tap do |output| + types.each { |type| assert_match /Foo#{type.to_s.camelize}Test/, output } + assert_match /7 tests, 7 assertions, 0 failures/, output + end + end + + private + def run_test_command(arguments = 'test/unit/test_test.rb') + Dir.chdir(app_path) { `bundle exec rails test #{arguments}` } + end + + def create_schema + app_file 'db/schema.rb', '' + end + + def redirect_stderr(target_stream) + previous_stderr = STDERR.dup + $stderr.reopen(target_stream) + yield + target_stream.rewind + ensure + $stderr = previous_stderr + end + + def create_test_file(path = :unit, name = 'test') + app_file "test/#{path}/#{name}_test.rb", <<-RUBY + require 'test_helper' + + class #{name.camelize}Test < ActiveSupport::TestCase + def test_truth + puts "#{name.camelize}Test" + assert true + end + end + RUBY + end + end +end -- cgit v1.2.3 From 176b57c5430ddae7668114994c35b3293b0a05a5 Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Fri, 1 Feb 2013 17:21:09 -0500 Subject: Add support for MiniTest flags in TestRunner Any flags that got set will be passed through to MiniTest::Unit.runner, such as `-n`, `-s-, and `-v`. --- railties/lib/rails/commands.rb | 15 ++--- railties/lib/rails/commands/test_runner.rb | 91 ++++++++++++++++++--------- railties/test/application/test_runner_test.rb | 21 +++++++ 3 files changed, 88 insertions(+), 39 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index c76af7d01f..2984999a3c 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -83,15 +83,12 @@ when 'server' when 'test' $LOAD_PATH.unshift("./test") require 'rails/commands/test_runner' - if ["-h", "--help"].include?(ARGV.first) - Rails::TestRunner.help_message - exit - else - require APP_PATH - Rails.application.require_environment! - Rails.application.load_tasks - Rails::TestRunner.start(ARGV) - end + options = Rails::TestRunner.parse_arguments(ARGV) + + require APP_PATH + Rails.application.require_environment! + Rails.application.load_tasks + Rails::TestRunner.start(ARGV, options) when 'dbconsole' require 'rails/commands/dbconsole' diff --git a/railties/lib/rails/commands/test_runner.rb b/railties/lib/rails/commands/test_runner.rb index a65b508505..33c32bb94f 100644 --- a/railties/lib/rails/commands/test_runner.rb +++ b/railties/lib/rails/commands/test_runner.rb @@ -9,54 +9,85 @@ module Rails # of file to a new +TestRunner+ object, then invoke the evaluation. If # the argument is not a test suite name, it will be treated as a file # name and passed to the +TestRunner+ instance right away. - def start(arguments) - case arguments.first + def start(files, options) + case files.first when nil - new(Dir['test/**/*_test.rb']).run + new(Dir['test/**/*_test.rb'], options).run when 'models' - new(Dir['test/models/**/*_test.rb']).run + new(Dir['test/models/**/*_test.rb'], options).run when 'helpers' - new(Dir['test/helpers/**/*_test.rb']).run + new(Dir['test/helpers/**/*_test.rb'], options).run when 'units' - new(Dir['test/{models,helpers,unit}/**/*_test.rb']).run + new(Dir['test/{models,helpers,unit}/**/*_test.rb'], options).run when 'controllers' - new(Dir['test/controllers/**/*_test.rb']).run + new(Dir['test/controllers/**/*_test.rb'], options).run when 'mailers' - new(Dir['test/mailers/**/*_test.rb']).run + new(Dir['test/mailers/**/*_test.rb'], options).run when 'functionals' - new(Dir['test/{controllers,mailers,functional}/**/*_test.rb']).run + new(Dir['test/{controllers,mailers,functional}/**/*_test.rb'], options).run when 'integration' - new(Dir['test/integration/**/*_test.rb']).run + new(Dir['test/integration/**/*_test.rb'], options).run else - new(arguments).run + new(files, options).run end end - # Print out the help message which listed all of the test suite names. - def help_message - puts "Usage: rails test [path to test file(s) or test suite type]" - puts "" - puts "Run single test file, or a test suite, under Rails'" - puts "environment. If the file name(s) or suit name is omitted," - puts "Rails will run all the test suites." - puts "" - puts "Support types of test suites:" - puts "-------------------------------------------------------------" - puts "* models (test/models/**/*)" - puts "* helpers (test/helpers/**/*)" - puts "* units (test/{models,helpers,unit}/**/*" - puts "* controllers (test/controllers/**/*)" - puts "* mailers (test/mailers/**/*)" - puts "* functionals (test/{controllers,mailers,functional}/**/*)" - puts "* integration (test/integration/**/*)" - puts "-------------------------------------------------------------" + # Parse arguments and set them as option flags + def parse_arguments(arguments) + options = {} + orig_arguments = arguments.dup + + OptionParser.new do |opts| + opts.banner = "Usage: rails test [path to test file(s) or test suite type]" + + opts.separator "" + opts.separator "Run single test file, or a test suite, under Rails'" + opts.separator "environment. If the file name(s) or suit name is omitted," + opts.separator "Rails will run all the test suites." + opts.separator "" + opts.separator "Specific options:" + + opts.on '-h', '--help', 'Display this help.' do + puts opts + exit + end + + opts.on '-s', '--seed SEED', Integer, "Sets random seed" do |m| + options[:seed] = m.to_i + end + + opts.on '-v', '--verbose', "Verbose. Show progress processing files." do + options[:verbose] = true + end + + opts.on '-n', '--name PATTERN', "Filter test names on pattern (e.g. /foo/)" do |a| + options[:filter] = a + end + + opts.separator "" + opts.separator "Support types of test suites:" + opts.separator "-------------------------------------------------------------" + opts.separator "* models (test/models/**/*)" + opts.separator "* helpers (test/helpers/**/*)" + opts.separator "* units (test/{models,helpers,unit}/**/*" + opts.separator "* controllers (test/controllers/**/*)" + opts.separator "* mailers (test/mailers/**/*)" + opts.separator "* functionals (test/{controllers,mailers,functional}/**/*)" + opts.separator "* integration (test/integration/**/*)" + opts.separator "-------------------------------------------------------------" + + opts.parse! arguments + orig_arguments -= arguments + end + options end end # Create a new +TestRunner+ object with a list of test file paths. - def initialize(files) + def initialize(files, options) @files = files Rake::Task['test:prepare'].invoke + MiniTest::Unit.runner.options = options MiniTest::Unit.output = SilentUntilSyncStream.new(MiniTest::Unit.output) end diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 49bce508ee..249bfd1d5d 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -149,6 +149,27 @@ module ApplicationTests end end + def test_run_named_test + app_file 'test/unit/chu_2_koi_test.rb', <<-RUBY + require 'test_helper' + + class Chu2KoiTest < ActiveSupport::TestCase + def test_rikka + puts 'Rikka' + end + + def test_sanae + puts 'Sanae' + end + end + RUBY + + run_test_command('test/unit/chu_2_koi_test.rb -n test_rikka').tap do |output| + assert_match /Rikka/, output + assert_no_match /Sanae/, output + end + end + private def run_test_command(arguments = 'test/unit/test_test.rb') Dir.chdir(app_path) { `bundle exec rails test #{arguments}` } -- cgit v1.2.3 From 1a0c58b2988a24a783b4f9a658ac629922125551 Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Wed, 6 Feb 2013 01:03:17 -0500 Subject: Load fixtures only when running suites, or `-f` * `rails test -f` will run the test suites with all fixtures loaded * New application will now generated without `fixtures :all` line enabled by default. --- railties/CHANGELOG.md | 8 ++++ railties/lib/rails/commands/test_runner.rb | 19 +++++++- .../rails/app/templates/test/test_helper.rb | 5 ++- railties/test/application/test_runner_test.rb | 51 ++++++++++++++++++++++ 4 files changed, 80 insertions(+), 3 deletions(-) (limited to 'railties') diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 6bf9b22a2d..4145938063 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -19,6 +19,14 @@ *Terence Lee* +* Rails now generate a `test/test_helper.rb` file with `fixtures :all` commented out by default, + since we don't want to force loading all fixtures for user when a single test is run. However, + fixtures are still going to be loaded automatically for test suites. + + To force all fixtures to be create in your database, use `rails test -f` to run your test. + + *Prem Sichanugrist* + * Add `rails test` command to run the test suite To run the whole test suite: diff --git a/railties/lib/rails/commands/test_runner.rb b/railties/lib/rails/commands/test_runner.rb index 33c32bb94f..ae901f05f8 100644 --- a/railties/lib/rails/commands/test_runner.rb +++ b/railties/lib/rails/commands/test_runner.rb @@ -9,7 +9,10 @@ module Rails # of file to a new +TestRunner+ object, then invoke the evaluation. If # the argument is not a test suite name, it will be treated as a file # name and passed to the +TestRunner+ instance right away. - def start(files, options) + def start(files, options = {}) + original_fixtures_options = options.delete(:fixtures) + options[:fixtures] = true + case files.first when nil new(Dir['test/**/*_test.rb'], options).run @@ -28,6 +31,7 @@ module Rails when 'integration' new(Dir['test/integration/**/*_test.rb'], options).run else + options[:fixtures] = original_fixtures_options new(files, options).run end end @@ -52,6 +56,10 @@ module Rails exit end + opts.on '-f', '--fixtures', 'Load fixtures in test/fixtures/ before running the tests' do + options[:fixtures] = true + end + opts.on '-s', '--seed SEED', Integer, "Sets random seed" do |m| options[:seed] = m.to_i end @@ -87,6 +95,15 @@ module Rails def initialize(files, options) @files = files Rake::Task['test:prepare'].invoke + + if options.delete(:fixtures) + if defined?(ActiveRecord::Base) + ActiveSupport::TestCase.send :include, ActiveRecord::TestFixtures + ActiveSupport::TestCase.fixture_path = "#{Rails.root}/test/fixtures/" + ActiveSupport::TestCase.fixtures :all + end + end + MiniTest::Unit.runner.options = options MiniTest::Unit.output = SilentUntilSyncStream.new(MiniTest::Unit.output) end diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index 9afda2d0df..754e99e09f 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb @@ -6,11 +6,12 @@ class ActiveSupport::TestCase <% unless options[:skip_active_record] -%> ActiveRecord::Migration.check_pending! - # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. + # Uncomment the `fixtures` line below to setup all fixtures in test/fixtures/*.yml for all tests + # in alphabetical order. # # Note: You'll currently still have to declare fixtures explicitly in integration tests # -- they do not yet inherit this setting - fixtures :all + # fixtures :all <% end -%> # Add more helper methods to be used by all tests here... diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 249bfd1d5d..71e2b403af 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -1,4 +1,5 @@ require 'isolation/abstract_unit' +require 'active_support/core_ext/string/strip' module ApplicationTests class TestRunnerTest < ActiveSupport::TestCase @@ -170,11 +171,61 @@ module ApplicationTests end end + def test_not_load_fixtures_when_running_single_test + create_model_with_fixture + create_fixture_test :models, 'user' + assert_match /0 users/, run_test_command('test/models/user_test.rb') + assert_match /3 users/, run_test_command('test/models/user_test.rb -f') + end + + def test_load_fixtures_when_running_test_suites + create_model_with_fixture + types = [:models, :helpers, [:units, :unit], :controllers, :mailers, + [:functionals, :functional], :integration] + + types.each do |type, directory| + directory ||= type + create_fixture_test directory + assert_match /3 users/, run_test_command(type) + Dir.chdir(app_path) { FileUtils.rm_f "test/#{directory}" } + end + end + private def run_test_command(arguments = 'test/unit/test_test.rb') Dir.chdir(app_path) { `bundle exec rails test #{arguments}` } end + def create_model_with_fixture + script 'generate model user name:string' + + app_file 'test/fixtures/users.yml', <<-YAML.strip_heredoc + vampire: + id: 1 + name: Koyomi Araragi + crab: + id: 2 + name: Senjougahara Hitagi + cat: + id: 3 + name: Tsubasa Hanekawa + YAML + + Dir.chdir(app_path) { `bundle exec rake db:migrate` } + end + + def create_fixture_test(path = :unit, name = 'test') + app_file "test/#{path}/#{name}_test.rb", <<-RUBY + require 'test_helper' + + class #{name.camelize}Test < ActiveSupport::TestCase + def test_fixture + puts "\#{User.count} users (\#{__FILE__})" + end + end + RUBY + end + def create_schema app_file 'db/schema.rb', '' end -- cgit v1.2.3 From df85dfa6fa6f7ae9a0b72eb9b9a254d2d5560f38 Mon Sep 17 00:00:00 2001 From: Dalibor Nasevic Date: Fri, 8 Feb 2013 00:53:11 +0100 Subject: Improve wording for rails test command --- railties/CHANGELOG.md | 19 +++++++----- railties/lib/rails/commands/test_runner.rb | 34 +++++++++++----------- .../rails/app/templates/test/test_helper.rb | 4 +-- railties/test/application/test_runner_test.rb | 16 +++++----- 4 files changed, 38 insertions(+), 35 deletions(-) (limited to 'railties') diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index 4145938063..e3b1bc37c6 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -19,7 +19,7 @@ *Terence Lee* -* Rails now generate a `test/test_helper.rb` file with `fixtures :all` commented out by default, +* Rails now generates a `test/test_helper.rb` file with `fixtures :all` commented out by default, since we don't want to force loading all fixtures for user when a single test is run. However, fixtures are still going to be loaded automatically for test suites. @@ -27,24 +27,27 @@ *Prem Sichanugrist* -* Add `rails test` command to run the test suite +* Add `rails test` command for running tests - To run the whole test suite: + To run all tests: $ rails test - To run the test file(s): + To run a test suite + + $ rails test [models,helpers,units,controllers,mailers,...] + + To run a selected test file(s): $ rails test test/unit/foo_test.rb [test/unit/bar_test.rb ...] - To run the test suite + To run a single test from a test file - $ rails test [models,helpers,units,controllers,mailers,...] + $ rails test test/unit/foo_test.rb -n test_the_truth For more information, see `rails test --help`. - This command will eventually replacing `rake test:*`, and `rake test` - command will actually invoking `rails test` instead. + This command will eventually replace `rake test:*` and `rake test` tasks *Prem Sichanugrist and Chris Toomey* diff --git a/railties/lib/rails/commands/test_runner.rb b/railties/lib/rails/commands/test_runner.rb index ae901f05f8..92c4d4e593 100644 --- a/railties/lib/rails/commands/test_runner.rb +++ b/railties/lib/rails/commands/test_runner.rb @@ -2,13 +2,13 @@ require 'optparse' require 'minitest/unit' module Rails - # Handling the all the logic behind +rails test+ command. + # Handles all logic behind +rails test+ command. class TestRunner class << self - # Parse the test suite name from the arguments array and pass in a list - # of file to a new +TestRunner+ object, then invoke the evaluation. If - # the argument is not a test suite name, it will be treated as a file - # name and passed to the +TestRunner+ instance right away. + # Creates a new +TestRunner+ object with an array of test files to run + # based on the arguments. When no arguments are provided, it runs all test + # files. When a suite argument is provided, it runs only the test files in + # that suite. Otherwise, it runs the specified test file(s). def start(files, options = {}) original_fixtures_options = options.delete(:fixtures) options[:fixtures] = true @@ -36,18 +36,18 @@ module Rails end end - # Parse arguments and set them as option flags + # Parses arguments and sets them as option flags def parse_arguments(arguments) options = {} orig_arguments = arguments.dup OptionParser.new do |opts| - opts.banner = "Usage: rails test [path to test file(s) or test suite type]" + opts.banner = "Usage: rails test [path to test file(s) or test suite]" opts.separator "" - opts.separator "Run single test file, or a test suite, under Rails'" + opts.separator "Run a specific test file(s) or a test suite, under Rails'" opts.separator "environment. If the file name(s) or suit name is omitted," - opts.separator "Rails will run all the test suites." + opts.separator "Rails will run all tests." opts.separator "" opts.separator "Specific options:" @@ -91,7 +91,7 @@ module Rails end end - # Create a new +TestRunner+ object with a list of test file paths. + # Creates a new +TestRunner+ object with a list of test file paths. def initialize(files, options) @files = files Rake::Task['test:prepare'].invoke @@ -108,25 +108,25 @@ module Rails MiniTest::Unit.output = SilentUntilSyncStream.new(MiniTest::Unit.output) end - # Run the test files by evaluate each of them. + # Runs test files by evaluating each of them. def run @files.each { |filename| load(filename) } end # A null stream object which ignores everything until +sync+ has been set - # to true. This is only to be used to silence unnecessary output from - # MiniTest, as MiniTest calls +output.sync = true+ right before output the - # first test result. + # to true. This is only used to silence unnecessary output from MiniTest, + # as MiniTest calls +output.sync = true+ right before it outputs the first + # test result. class SilentUntilSyncStream < File - # Create a +SilentUntilSyncStream+ object by given a stream object that - # this stream should set +MiniTest::Unit.output+ to after +sync+ has been + # Creates a +SilentUntilSyncStream+ object by giving it a target stream + # object that will be assigned to +MiniTest::Unit.output+ after +sync+ is # set to true. def initialize(target_stream) @target_stream = target_stream super(File::NULL, 'w') end - # Swap +MiniTest::Unit.output+ to another stream when +sync+ is true. + # Swaps +MiniTest::Unit.output+ to another stream when +sync+ is true. def sync=(sync) if sync @target_stream.sync = true diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index 754e99e09f..f0aeeee827 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb @@ -6,8 +6,8 @@ class ActiveSupport::TestCase <% unless options[:skip_active_record] -%> ActiveRecord::Migration.check_pending! - # Uncomment the `fixtures` line below to setup all fixtures in test/fixtures/*.yml for all tests - # in alphabetical order. + # Uncomment the `fixtures :all` line below to setup all fixtures in test/fixtures/*.yml + # for all tests in alphabetical order. # # Note: You'll currently still have to declare fixtures explicitly in integration tests # -- they do not yet inherit this setting diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 71e2b403af..810748682a 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -141,11 +141,11 @@ module ApplicationTests end end - def test_run_whole_suite - types = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration] - types.each { |type| create_test_file type, "foo_#{type}" } + def test_run_all_suites + suites = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration] + suites.each { |suite| create_test_file suite, "foo_#{suite}" } run_test_command('') .tap do |output| - types.each { |type| assert_match /Foo#{type.to_s.camelize}Test/, output } + suites.each { |suite| assert_match /Foo#{suite.to_s.camelize}Test/, output } assert_match /7 tests, 7 assertions, 0 failures/, output end end @@ -180,13 +180,13 @@ module ApplicationTests def test_load_fixtures_when_running_test_suites create_model_with_fixture - types = [:models, :helpers, [:units, :unit], :controllers, :mailers, + suites = [:models, :helpers, [:units, :unit], :controllers, :mailers, [:functionals, :functional], :integration] - types.each do |type, directory| - directory ||= type + suites.each do |suite, directory| + directory ||= suite create_fixture_test directory - assert_match /3 users/, run_test_command(type) + assert_match /3 users/, run_test_command(suite) Dir.chdir(app_path) { FileUtils.rm_f "test/#{directory}" } end end -- cgit v1.2.3 From b51673fbd9563bd3ffa22e22255ca1cef80cfb6d Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Mon, 25 Feb 2013 17:04:01 -0500 Subject: Update Rake tasks to call `rails test` instead Also, print out deprecation warning for other rake tasks except `rake test` and `rake` (default) --- railties/lib/rails/test_unit/testing.rake | 80 +++++++++++-------------------- railties/test/application/rake_test.rb | 23 +++++---- 2 files changed, 41 insertions(+), 62 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake index 44485d9b14..de44bf9e4d 100644 --- a/railties/lib/rails/test_unit/testing.rake +++ b/railties/lib/rails/test_unit/testing.rake @@ -1,6 +1,7 @@ require 'rbconfig' require 'rake/testtask' require 'rails/test_unit/sub_test_task' +require 'active_support/deprecation' TEST_CHANGES_SINCE = Time.now - 600 @@ -47,7 +48,11 @@ task default: :test desc 'Runs test:units, test:functionals, test:integration together' task :test do - Rake::Task[ENV['TEST'] ? 'test:single' : 'test:run'].invoke + if ENV['TEST'] + exec "bundle exec rails test #{ENV['TEST'].inspect}" + else + exec 'bundle exec rails test' + end end namespace :test do @@ -56,19 +61,8 @@ namespace :test do end task :run do - errors = %w(test:units test:functionals test:integration).collect do |task| - begin - Rake::Task[task].invoke - nil - rescue => e - { task: task, exception: e } - end - end.compact - - if errors.any? - puts errors.map { |e| "Errors running #{e[:task]}! #{e[:exception].inspect}" }.join("\n") - abort - end + ActiveSupport::Deprecation.warn "`rake test:run` is deprecated. Please use `rails test`." + exec 'bundle exec rails test' end # Inspired by: http://ngauthier.com/2012/02/quick-tests-with-bash.html @@ -83,7 +77,13 @@ namespace :test do task :db => %w[db:test:prepare test:all] end - Rake::TestTask.new(recent: "test:prepare") do |t| + # Display deprecation message + task :deprecated do + task_name = ARGV.first + ActiveSupport::Deprecation.warn "`rake #{ARGV.first}` is deprecated with no replacement." + end + + Rake::TestTask.new(recent: ["test:deprecated", "test:prepare"]) do |t| since = TEST_CHANGES_SINCE touched = FileList['test/**/*_test.rb'].select { |path| File.mtime(path) > since } + recent_tests('app/models/**/*.rb', 'test/models', since) + @@ -94,9 +94,9 @@ namespace :test do t.libs << 'test' t.test_files = touched.uniq end - Rake::Task['test:recent'].comment = "Test recent changes" + Rake::Task['test:recent'].comment = "Deprecated; Test recent changes" - Rake::TestTask.new(uncommitted: "test:prepare") do |t| + Rake::TestTask.new(uncommitted: ["test:deprecated", "test:prepare"]) do |t| def t.file_list if File.directory?(".svn") changed_since_checkin = silence_stderr { `svn status` }.split.map { |path| path.chomp[7 .. -1] } @@ -118,44 +118,20 @@ namespace :test do t.libs << 'test' end - Rake::Task['test:uncommitted'].comment = "Test changes since last checkin (only Subversion and Git)" - - Rake::TestTask.new(single: "test:prepare") do |t| - t.libs << "test" - end - - Rails::SubTestTask.new(models: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/models/**/*_test.rb' - end - - Rails::SubTestTask.new(helpers: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/helpers/**/*_test.rb' - end + Rake::Task['test:uncommitted'].comment = "Deprecated; Test changes since last checkin (only Subversion and Git)" - Rails::SubTestTask.new(units: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/{models,helpers,unit}/**/*_test.rb' + desc "Deprecated; Please use `rails test \"#{ENV['TEST']}\"`" + task :single do + ActiveSupport::Deprecation.warn "`rake test:single` is deprecated. Please use `rails test \"#{ENV['TEST']}\"`." + exec "bundle exec rails test #{test_suit_name}" end - Rails::SubTestTask.new(controllers: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/controllers/**/*_test.rb' - end + [:models, :helpers, :units, :controllers, :functionals, :integration].each do |test_suit_name| + desc "Deprecated; Please use `rails test #{test_suit_name}`" + task test_suit_name do + ActiveSupport::Deprecation.warn "`rake test:#{test_suit_name}` is deprecated. Please use `rails test #{test_suit_name}`." - Rails::SubTestTask.new(mailers: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/mailers/**/*_test.rb' - end - - Rails::SubTestTask.new(functionals: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/{controllers,mailers,functional}/**/*_test.rb' - end - - Rails::SubTestTask.new(integration: "test:prepare") do |t| - t.libs << "test" - t.pattern = 'test/integration/**/*_test.rb' + exec "bundle exec rails test #{test_suit_name}" + end end end diff --git a/railties/test/application/rake_test.rb b/railties/test/application/rake_test.rb index 09f2ad1209..a9e0e1bcb7 100644 --- a/railties/test/application/rake_test.rb +++ b/railties/test/application/rake_test.rb @@ -91,19 +91,9 @@ module ApplicationTests raise 'models' RUBY - app_file "test/controllers/one_controller_test.rb", <<-RUBY - raise 'controllers' - RUBY - - app_file "test/integration/one_integration_test.rb", <<-RUBY - raise 'integration' - RUBY - silence_stderr do output = Dir.chdir(app_path) { `rake test 2>&1` } assert_match 'models', output - assert_match 'controllers', output - assert_match 'integration', output end end @@ -135,6 +125,19 @@ module ApplicationTests end end + def test_rake_test_deprecation_messages + Dir.chdir(app_path){ `rails generate scaffold user name:string` } + Dir.chdir(app_path){ `rake db:migrate` } + + %w(run recent uncommitted models helpers units controllers functionals integration).each do |test_suit_name| + output = Dir.chdir(app_path) { `rake test:#{test_suit_name} 2>&1` } + assert_match /DEPRECATION WARNING: `rake test:#{test_suit_name}` is deprecated/, output + end + + assert_match /DEPRECATION WARNING: `rake test:single` is deprecated/, + Dir.chdir(app_path) { `rake test:single TEST=test/models/user_test.rb 2>&1` } + end + def test_rake_routes_calls_the_route_inspector app_file "config/routes.rb", <<-RUBY AppTemplate::Application.routes.draw do -- cgit v1.2.3 From 3ed41e579e45464aa6e6342783b77f9ec29e339c Mon Sep 17 00:00:00 2001 From: Prem Sichanugrist Date: Sat, 9 Mar 2013 16:03:09 -0500 Subject: Make sure that `rails test` load test in test env --- railties/lib/rails/commands.rb | 3 +- railties/lib/rails/commands/test_runner.rb | 12 ++++-- .../rails/app/templates/test/test_helper.rb | 2 +- railties/test/application/test_runner_test.rb | 45 +++++++++++++++++++++- 4 files changed, 55 insertions(+), 7 deletions(-) (limited to 'railties') diff --git a/railties/lib/rails/commands.rb b/railties/lib/rails/commands.rb index 2984999a3c..41d3722c18 100644 --- a/railties/lib/rails/commands.rb +++ b/railties/lib/rails/commands.rb @@ -84,10 +84,9 @@ when 'test' $LOAD_PATH.unshift("./test") require 'rails/commands/test_runner' options = Rails::TestRunner.parse_arguments(ARGV) + ENV['RAILS_ENV'] ||= options[:environment] || 'test' require APP_PATH - Rails.application.require_environment! - Rails.application.load_tasks Rails::TestRunner.start(ARGV, options) when 'dbconsole' diff --git a/railties/lib/rails/commands/test_runner.rb b/railties/lib/rails/commands/test_runner.rb index 92c4d4e593..d8857bd183 100644 --- a/railties/lib/rails/commands/test_runner.rb +++ b/railties/lib/rails/commands/test_runner.rb @@ -56,6 +56,10 @@ module Rails exit end + opts.on '-e', '--environment NAME', String, 'Specifies the environment to run this test under' do |e| + options[:environment] = e + end + opts.on '-f', '--fixtures', 'Load fixtures in test/fixtures/ before running the tests' do options[:fixtures] = true end @@ -68,8 +72,8 @@ module Rails options[:verbose] = true end - opts.on '-n', '--name PATTERN', "Filter test names on pattern (e.g. /foo/)" do |a| - options[:filter] = a + opts.on '-n', '--name PATTERN', "Filter test names on pattern (e.g. /foo/)" do |n| + options[:filter] = n end opts.separator "" @@ -94,7 +98,9 @@ module Rails # Creates a new +TestRunner+ object with a list of test file paths. def initialize(files, options) @files = files - Rake::Task['test:prepare'].invoke + + Rails.application.load_tasks + Rake::Task['db:test:load'].invoke if options.delete(:fixtures) if defined?(ActiveRecord::Base) diff --git a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb index f0aeeee827..ca40914d3b 100644 --- a/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb +++ b/railties/lib/rails/generators/rails/app/templates/test/test_helper.rb @@ -1,4 +1,4 @@ -ENV["RAILS_ENV"] = "test" +ENV["RAILS_ENV"] ||= "test" require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' diff --git a/railties/test/application/test_runner_test.rb b/railties/test/application/test_runner_test.rb index 810748682a..7a5a428845 100644 --- a/railties/test/application/test_runner_test.rb +++ b/railties/test/application/test_runner_test.rb @@ -191,6 +191,39 @@ module ApplicationTests end end + def test_run_different_environment_using_env_var + app_file 'test/unit/env_test.rb', <<-RUBY + require 'test_helper' + + class EnvTest < ActiveSupport::TestCase + def test_env + puts Rails.env + end + end + RUBY + + assert_match /development/, Dir.chdir(app_path) { `RAILS_ENV=development bundle exec rails test test/unit/env_test.rb` } + end + + def test_run_different_environment_using_e_tag + app_file 'test/unit/env_test.rb', <<-RUBY + require 'test_helper' + + class EnvTest < ActiveSupport::TestCase + def test_env + puts Rails.env + end + end + RUBY + + assert_match /development/, run_test_command('-e development test/unit/env_test.rb') + end + + def test_generated_scaffold_works_with_rails_test + create_scaffold + assert_match /0 failures, 0 errors, 0 skips/, run_test_command('') + end + private def run_test_command(arguments = 'test/unit/test_test.rb') Dir.chdir(app_path) { `bundle exec rails test #{arguments}` } @@ -211,7 +244,7 @@ module ApplicationTests name: Tsubasa Hanekawa YAML - Dir.chdir(app_path) { `bundle exec rake db:migrate` } + run_migration end def create_fixture_test(path = :unit, name = 'test') @@ -251,5 +284,15 @@ module ApplicationTests end RUBY end + + def create_scaffold + script 'generate scaffold user name:string' + Dir.chdir(app_path) { File.exist?('app/models/user.rb') } + run_migration + end + + def run_migration + Dir.chdir(app_path) { `bundle exec rake db:migrate` } + end end end -- cgit v1.2.3