aboutsummaryrefslogtreecommitdiffstats
path: root/railties/lib/rails/test_unit
diff options
context:
space:
mode:
Diffstat (limited to 'railties/lib/rails/test_unit')
-rw-r--r--railties/lib/rails/test_unit/minitest_plugin.rb88
-rw-r--r--railties/lib/rails/test_unit/reporter.rb64
-rw-r--r--railties/lib/rails/test_unit/sub_test_task.rb126
-rw-r--r--railties/lib/rails/test_unit/test_requirer.rb28
-rw-r--r--railties/lib/rails/test_unit/testing.rake51
5 files changed, 204 insertions, 153 deletions
diff --git a/railties/lib/rails/test_unit/minitest_plugin.rb b/railties/lib/rails/test_unit/minitest_plugin.rb
new file mode 100644
index 0000000000..d1ba35a5ec
--- /dev/null
+++ b/railties/lib/rails/test_unit/minitest_plugin.rb
@@ -0,0 +1,88 @@
+require "active_support/core_ext/module/attribute_accessors"
+require "rails/test_unit/reporter"
+require "rails/test_unit/test_requirer"
+
+module Minitest
+ mattr_accessor(:hide_aggregated_results) { false }
+
+ module AggregatedResultSuppresion
+ def aggregated_results
+ super unless Minitest.hide_aggregated_results
+ end
+ end
+
+ SummaryReporter.prepend AggregatedResultSuppresion
+
+ def self.plugin_rails_options(opts, options)
+ opts.separator ""
+ opts.separator "Usage: bin/rails test [options] [files or directories]"
+ opts.separator "You can run a single test by appending a line number to a filename:"
+ opts.separator ""
+ opts.separator " bin/rails test test/models/user_test.rb:27"
+ opts.separator ""
+ opts.separator "You can run multiple files and directories at the same time:"
+ opts.separator ""
+ opts.separator " bin/rails test test/controllers test/integration/login_test.rb"
+ opts.separator ""
+ opts.separator "By default test failures and errors are reported inline during a run."
+ opts.separator ""
+
+ opts.separator "Rails options:"
+ opts.on("-e", "--environment ENV",
+ "Run tests in the ENV environment") do |env|
+ options[:environment] = env.strip
+ end
+
+ opts.on("-b", "--backtrace",
+ "Show the complete backtrace") do
+ options[:full_backtrace] = true
+ end
+
+ opts.on("-d", "--defer-output",
+ "Output test failures and errors after the test run") do
+ options[:output_inline] = false
+ end
+
+ opts.on("-f", "--fail-fast",
+ "Abort test run on first failure") do
+ options[:fail_fast] = true
+ end
+
+ options[:output_inline] = true
+ options[:patterns] = opts.order!
+ end
+
+ # Running several Rake tasks in a single command would trip up the runner,
+ # as the patterns would also contain the other Rake tasks.
+ def self.rake_run(patterns) # :nodoc:
+ @rake_patterns = patterns
+ run
+ end
+
+ def self.plugin_rails_init(options)
+ self.run_with_rails_extension = true
+
+ ENV["RAILS_ENV"] = options[:environment] || "test"
+
+ unless run_with_autorun
+ patterns = defined?(@rake_patterns) ? @rake_patterns : options[:patterns]
+ ::Rails::TestRequirer.require_files(patterns)
+ end
+
+ unless options[:full_backtrace] || ENV["BACKTRACE"]
+ # Plugin can run without Rails loaded, check before filtering.
+ Minitest.backtrace_filter = ::Rails.backtrace_cleaner if ::Rails.respond_to?(:backtrace_cleaner)
+ end
+
+ # Disable the extra failure output after a run, unless output is deferred.
+ self.hide_aggregated_results = options[:output_inline]
+
+ self.reporter << ::Rails::TestUnitReporter.new(options[:io], options)
+ end
+
+ mattr_accessor(:run_with_autorun) { false }
+ mattr_accessor(:run_with_rails_extension) { false }
+end
+
+Minitest.load_plugins
+Minitest.extensions << 'rails'
diff --git a/railties/lib/rails/test_unit/reporter.rb b/railties/lib/rails/test_unit/reporter.rb
new file mode 100644
index 0000000000..e1fe92a11b
--- /dev/null
+++ b/railties/lib/rails/test_unit/reporter.rb
@@ -0,0 +1,64 @@
+require "active_support/core_ext/class/attribute"
+require "minitest"
+
+module Rails
+ class TestUnitReporter < Minitest::StatisticsReporter
+ class_attribute :executable
+ self.executable = "bin/rails test"
+
+ def record(result)
+ super
+
+ if output_inline? && result.failure && (!result.skipped? || options[:verbose])
+ io.puts
+ io.puts
+ io.puts result.failures.map(&:message)
+ io.puts
+ io.puts format_rerun_snippet(result)
+ io.puts
+ end
+
+ if fail_fast? && result.failure && !result.error? && !result.skipped?
+ raise Interrupt
+ end
+ end
+
+ def report
+ return if output_inline? || filtered_results.empty?
+ io.puts
+ io.puts "Failed tests:"
+ io.puts
+ io.puts aggregated_results
+ end
+
+ def aggregated_results # :nodoc:
+ filtered_results.map { |result| format_rerun_snippet(result) }.join "\n"
+ end
+
+ def filtered_results
+ if options[:verbose]
+ results
+ else
+ results.reject(&:skipped?)
+ end
+ end
+
+ def relative_path_for(file)
+ file.sub(/^#{Rails.root}\/?/, '')
+ end
+
+ private
+ def output_inline?
+ options[:output_inline]
+ end
+
+ def fail_fast?
+ options[:fail_fast]
+ end
+
+ def format_rerun_snippet(result)
+ location, line = result.method(result.name).source_location
+ "#{self.executable} #{relative_path_for(location)}:#{line}"
+ end
+ end
+end
diff --git a/railties/lib/rails/test_unit/sub_test_task.rb b/railties/lib/rails/test_unit/sub_test_task.rb
deleted file mode 100644
index 6fa96d2ced..0000000000
--- a/railties/lib/rails/test_unit/sub_test_task.rb
+++ /dev/null
@@ -1,126 +0,0 @@
-require 'rake/testtask'
-
-module Rails
- class TestTask < Rake::TestTask # :nodoc: all
- # A utility class which is used primarily in "rails/test_unit/testing.rake"
- # to help define rake tasks corresponding to <tt>rake test</tt>.
- #
- # This class takes a TestInfo class and defines the appropriate rake task
- # based on the information, then invokes it.
- class TestCreator # :nodoc:
- def initialize(info)
- @info = info
- end
-
- def invoke_rake_task
- if @info.files.any?
- create_and_run_single_test
- reset_application_tasks
- else
- Rake::Task[ENV['TEST'] ? 'test:single' : 'test:run'].invoke
- end
- end
-
- private
-
- def create_and_run_single_test
- Rails::TestTask.new('test:single') { |t|
- t.test_files = @info.files
- }
- ENV['TESTOPTS'] ||= @info.opts
- Rake::Task['test:single'].invoke
- end
-
- def reset_application_tasks
- Rake.application.top_level_tasks.replace @info.tasks
- end
- end
-
- # This is a utility class used by the <tt>TestTask::TestCreator</tt> class.
- # This class takes a set of test tasks and checks to see if they correspond
- # to test files (or can be transformed into test files). Calling <tt>files</tt>
- # provides the set of test files and is used when initializing tests after
- # a call to <tt>rake test</tt>.
- class TestInfo # :nodoc:
- def initialize(tasks)
- @tasks = tasks
- @files = nil
- end
-
- def files
- @files ||= @tasks.map { |task|
- [task, translate(task)].find { |file| test_file?(file) }
- }.compact
- end
-
- def translate(file)
- if file =~ /^app\/(.*)$/
- "test/#{$1.sub(/\.rb$/, '')}_test.rb"
- else
- "test/#{file}_test.rb"
- end
- end
-
- def tasks
- @tasks - test_file_tasks - opt_names
- end
-
- def opts
- opts = opt_names
- if opts.any?
- "-n #{opts.join ' '}"
- end
- end
-
- private
-
- def test_file_tasks
- @tasks.find_all { |task|
- [task, translate(task)].any? { |file| test_file?(file) }
- }
- end
-
- def test_file?(file)
- file =~ /^test/ && File.file?(file) && !File.directory?(file)
- end
-
- def opt_names
- (@tasks - test_file_tasks).reject { |t| task_defined? t }
- end
-
- def task_defined?(task)
- Rake::Task.task_defined? task
- end
- end
-
- def self.test_creator(tasks)
- info = TestInfo.new(tasks)
- TestCreator.new(info)
- end
-
- def initialize(name = :test)
- super
- @libs << "test" # lib *and* test seem like a better default
- end
-
- 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
- end
-
- # Silence the default description to cut down on `rake -T` noise.
- class SubTestTask < Rake::TestTask # :nodoc:
- def desc(string)
- # Ignore the description.
- end
- end
-end
diff --git a/railties/lib/rails/test_unit/test_requirer.rb b/railties/lib/rails/test_unit/test_requirer.rb
new file mode 100644
index 0000000000..83d2c55ffd
--- /dev/null
+++ b/railties/lib/rails/test_unit/test_requirer.rb
@@ -0,0 +1,28 @@
+require 'active_support/core_ext/object/blank'
+require 'rake/file_list'
+
+module Rails
+ class TestRequirer # :nodoc:
+ class << self
+ def require_files(patterns)
+ patterns = expand_patterns(patterns)
+
+ Rake::FileList[patterns.compact.presence || 'test/**/*_test.rb'].to_a.each do |file|
+ require File.expand_path(file)
+ end
+ end
+
+ private
+ def expand_patterns(patterns)
+ patterns.map do |arg|
+ arg = arg.gsub(/:(\d+)?$/, '')
+ if Dir.exist?(arg)
+ "#{arg}/**/*_test.rb"
+ else
+ arg
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/railties/lib/rails/test_unit/testing.rake b/railties/lib/rails/test_unit/testing.rake
index 285e2ce846..6676c6a079 100644
--- a/railties/lib/rails/test_unit/testing.rake
+++ b/railties/lib/rails/test_unit/testing.rake
@@ -1,48 +1,45 @@
-require 'rake/testtask'
-require 'rails/test_unit/sub_test_task'
+gem 'minitest'
+require 'minitest'
+require 'rails/test_unit/minitest_plugin'
task default: :test
-desc 'Runs test:units, test:functionals, test:generators, test:integration together'
+desc "Runs all tests in test folder"
task :test do
- Rails::TestTask.test_creator(Rake.application.top_level_tasks).invoke_rake_task
+ $: << "test"
+ Minitest.rake_run(["test"])
end
namespace :test do
task :prepare do
- # Placeholder task for other Railtie and plugins to enhance. See Active Record for an example.
+ # Placeholder task for other Railtie and plugins to enhance.
+ # If used with Active Record, this task runs before the database schema is synchronized.
end
- task :run => ['test:units', 'test:functionals', 'test:generators', 'test:integration']
+ task :run => %w[test]
- # Inspired by: http://ngauthier.com/2012/02/quick-tests-with-bash.html
- desc "Run tests quickly by merging all types and not resetting db"
- Rails::TestTask.new(:all) do |t|
- t.pattern = "test/**/*_test.rb"
- end
-
- namespace :all do
- desc "Run tests quickly, but also reset db"
- task :db => %w[db:test:prepare test:all]
- end
-
- Rails::TestTask.new(single: "test:prepare")
+ desc "Run tests quickly, but also reset db"
+ task :db => %w[db:test:prepare test]
- ["models", "helpers", "controllers", "mailers", "integration"].each do |name|
- Rails::TestTask.new(name => "test:prepare") do |t|
- t.pattern = "test/#{name}/**/*_test.rb"
+ ["models", "helpers", "controllers", "mailers", "integration", "jobs"].each do |name|
+ task name => "test:prepare" do
+ $: << "test"
+ Minitest.rake_run(["test/#{name}"])
end
end
- Rails::TestTask.new(generators: "test:prepare") do |t|
- t.pattern = "test/lib/generators/**/*_test.rb"
+ task :generators => "test:prepare" do
+ $: << "test"
+ Minitest.rake_run(["test/lib/generators"])
end
- Rails::TestTask.new(units: "test:prepare") do |t|
- t.pattern = 'test/{models,helpers,unit}/**/*_test.rb'
+ task :units => "test:prepare" do
+ $: << "test"
+ Minitest.rake_run(["test/models", "test/helpers", "test/unit"])
end
- Rails::TestTask.new(functionals: "test:prepare") do |t|
- t.pattern = 'test/{controllers,mailers,functional}/**/*_test.rb'
+ task :functionals => "test:prepare" do
+ $: << "test"
+ Minitest.rake_run(["test/controllers", "test/mailers", "test/functional"])
end
end