Skip to content

Commit

Permalink
Run test:prepare unless exact tests are specified
Browse files Browse the repository at this point in the history
Follow-up to #46664.

In #46664, `bin/rails test` _without_ args, `bin/rails test:all`, and
`bin/rails test:system` were made to run the `test:prepare` task.
However `bin/rails test` _with_ args (e.g. `bin/rails test --seed 1234`)
and other `test:*` commands (e.g. `bin/rails test:models`) were not made
to do so.

This commit changes `bin/rails test` to always run `test:prepare` unless
exact tests are specified via path arguments (e.g. `bin/rails test
path/to/test.rb`) or a name pattern (e.g. `bin/rails test -n test_foo`).

This commit also refactors the testing Rake tasks so that all of the
logic regarding which files to load and whether to run `test:prepare` is
contained within the `TestCommand` class.
  • Loading branch information
jonathanhefner committed Feb 1, 2023
1 parent d7d93fa commit 613c20b
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 155 deletions.
50 changes: 18 additions & 32 deletions railties/lib/rails/commands/test/test_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,66 +27,52 @@ def help
end
end

def perform(*)
def perform(*args)
$LOAD_PATH << Rails::Command.root.join("test").to_s

Rails::TestUnit::Runner.parse_options(args)
run_prepare_task(args)
run_prepare_task if self.args.none?(EXACT_TEST_ARGUMENT_PATTERN)
Rails::TestUnit::Runner.run(args)
end

# Define Thor tasks to avoid going through Rake and booting twice when using bin/rails test:*
Rails::TestUnit::Runner::TEST_FOLDERS.each do |name|
desc name, "Run tests in test/#{name}"
define_method(name) do |*|
args.prepend("test/#{name}")
perform
define_method(name) do |*args|
perform("test/#{name}", *args)
end
end

desc "all", "Run all tests, including system tests"
def all(*)
@force_prepare = true
args.prepend("test/**/*_test.rb")
perform
def all(*args)
perform("test/**/*_test.rb", *args)
end

desc "functionals", "Run tests in test/controllers, test/mailers, and test/functional"
def functionals(*)
@force_prepare = true
args.prepend("test/controllers")
args.prepend("test/mailers")
args.prepend("test/functional")
perform
def functionals(*args)
perform("test/controllers", "test/mailers", "test/functional", *args)
end

desc "units", "Run tests in test/models, test/helpers, and test/unit"
def units(*)
@force_prepare = true
args.prepend("test/models")
args.prepend("test/helpers")
args.prepend("test/unit")
perform
def units(*args)
perform("test/models", "test/helpers", "test/unit", *args)
end

desc "system", "Run system tests only"
def system(*)
@force_prepare = true
args.prepend("test/system")
perform
def system(*args)
perform("test/system", *args)
end

desc "generators", "Run tests in test/lib/generators"
def generators(*)
args.prepend("test/lib/generators")
perform
def generators(*args)
perform("test/lib/generators", *args)
end

private
def run_prepare_task(args)
if @force_prepare || args.empty?
Rails::Command::RakeCommand.perform("test:prepare", [], {})
end
EXACT_TEST_ARGUMENT_PATTERN = /^-n|^--name\b|#{Rails::TestUnit::Runner::PATH_ARGUMENT_PATTERN}/

def run_prepare_task
Rails::Command::RakeCommand.perform("test:prepare", [], {})
rescue UnrecognizedCommandError => error
raise unless error.name == "test:prepare"
end
Expand Down
9 changes: 5 additions & 4 deletions railties/lib/rails/test_unit/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module Rails
module TestUnit
class Runner
TEST_FOLDERS = [:models, :helpers, :channels, :controllers, :mailers, :integration, :jobs, :mailboxes]
PATH_ARGUMENT_PATTERN = %r"^(?!/.+/$)[.\w]*[/\\]"
mattr_reader :filters, default: []

class << self
Expand All @@ -31,9 +32,9 @@ def parse_options(argv)
$VERBOSE = argv.delete_at(w_index) if w_index
end

def rake_run(argv = [])
def run_from_rake(test_command, argv = [])
# Ensure the tests run during the Rake Task action, not when the process exits
success = system("rails", "test", *argv, *Shellwords.split(ENV["TESTOPTS"] || ""))
success = system("rails", test_command, *argv, *Shellwords.split(ENV["TESTOPTS"] || ""))
success || exit(false)
end

Expand Down Expand Up @@ -62,7 +63,7 @@ def compose_filter(runnable, filter)
def extract_filters(argv)
# Extract absolute and relative paths but skip -n /.*/ regexp filters.
argv.filter_map do |path|
next unless path_argument?(path) && !regexp_filter?(path)
next unless path_argument?(path)

path = path.tr("\\", "/")
case
Expand Down Expand Up @@ -92,7 +93,7 @@ def regexp_filter?(arg)
end

def path_argument?(arg)
%r"^\.*[/\\]?\w+[/\\]".match?(arg)
PATH_ARGUMENT_PATTERN.match?(arg)
end

def list_tests(argv)
Expand Down
39 changes: 11 additions & 28 deletions railties/lib/rails/test_unit/testing.rake
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ task default: :test

desc "Run all tests in test folder except system ones"
task :test do
if ENV.key?("TEST")
Rails::TestUnit::Runner.rake_run([ENV["TEST"]])
else
Rails::TestUnit::Runner.rake_run
end
Rails::TestUnit::Runner.run_from_rake("test", Array(ENV["TEST"]))
end

namespace :test do
Expand All @@ -29,29 +25,16 @@ namespace :test do
success || exit(false)
end

Rails::TestUnit::Runner::TEST_FOLDERS.each do |name|
task name => "test:prepare" do
Rails::TestUnit::Runner.rake_run(["test/#{name}"])
[
*Rails::TestUnit::Runner::TEST_FOLDERS,
:all,
:generators,
:units,
:functionals,
:system,
].each do |name|
task name do
Rails::TestUnit::Runner.run_from_rake("test:#{name}")
end
end

task all: "test:prepare" do
Rails::TestUnit::Runner.rake_run(["test/**/*_test.rb"])
end

task generators: "test:prepare" do
Rails::TestUnit::Runner.rake_run(["test/lib/generators"])
end

task units: "test:prepare" do
Rails::TestUnit::Runner.rake_run(["test/models", "test/helpers", "test/unit"])
end

task functionals: "test:prepare" do
Rails::TestUnit::Runner.rake_run(["test/controllers", "test/mailers", "test/functional"])
end

task system: "test:prepare" do
Rails::TestUnit::Runner.rake_run(["test/system"])
end
end
91 changes: 0 additions & 91 deletions railties/test/application/test_runner_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1133,97 +1133,6 @@ def test_can_exclude_files_from_being_tested_via_rake_task_by_setting_DEFAULT_TE
assert_match "0 runs, 0 assertions, 0 failures, 0 errors, 0 skips", output
end

def test_rake_test_runs_test_prepare
app_file "Rakefile", <<~RUBY, "a"
task :echo do
puts "echo"
end
Rake::Task["test:prepare"].enhance(["echo"])
RUBY
create_test_file :models, "foo"
output = Dir.chdir(app_path) { `bin/rake test` }
assert_includes output, "echo"
assert_includes output, "1 runs, 1 assertions, 0 failures"
end

def test_rake_test_all_runs_test_prepare
app_file "Rakefile", <<~RUBY, "a"
task :echo do
puts "echo"
end
Rake::Task["test:prepare"].enhance(["echo"])
RUBY
create_test_file :models, "foo"
output = Dir.chdir(app_path) { `bin/rake test:all` }
assert_includes output, "echo"
assert_includes output, "1 runs, 1 assertions, 0 failures"
end

def test_rake_test_db_runs_test_prepare
app_file "Rakefile", <<~RUBY, "a"
task :echo do
puts "echo"
end
Rake::Task["test:prepare"].enhance(["echo"])
RUBY
create_test_file :models, "foo"
output = Dir.chdir(app_path) { `bin/rake test:db` }
assert_includes output, "echo"
assert_includes output, "1 runs, 1 assertions, 0 failures"
end

def test_rake_test_with_path_runs_test_prepare # unlike bin/rails test, bin/rake test does not accept a path argument - it always runs the whole suite
app_file "Rakefile", <<~RUBY, "a"
task :echo do
puts "echo"
end
Rake::Task["test:prepare"].enhance(["echo"])
RUBY
create_test_file :models, "foo"
output = Dir.chdir(app_path) { `bin/rake test test/models/foo_test.rb` }
assert_includes output, "echo"
assert_includes output, "1 runs, 1 assertions, 0 failures"
end

def test_rails_test_runs_test_prepare
app_file "Rakefile", <<~RUBY, "a"
task :echo do
puts "echo"
end
Rake::Task["test:prepare"].enhance(["echo"])
RUBY
create_test_file :models, "foo"
output = run_test_command("", allow_failure: false)
assert_includes output, "echo"
assert_includes output, "1 runs, 1 assertions, 0 failures"
end

def test_rails_all_test_runs_test_prepare
app_file "Rakefile", <<~RUBY, "a"
task :echo do
puts "echo"
end
Rake::Task["test:prepare"].enhance(["echo"])
RUBY
create_test_file :models, "foo"
output = rails "test:all", allow_failure: false
assert_includes output, "echo"
assert_includes output, "1 runs, 1 assertions, 0 failures"
end

def test_rails_test_with_path_does_not_run_test_prepare
app_file "Rakefile", <<~RUBY, "a"
task :echo do
puts "echo"
end
Rake::Task["test:prepare"].enhance(["echo"])
RUBY
create_test_file :models, "foo"
output = run_test_command("test/models/foo_test.rb", allow_failure: false)
assert_not_includes output, "echo"
assert_includes output, "1 runs, 1 assertions, 0 failures"
end

private
def run_test_command(arguments = "test/unit/test_test.rb", **opts)
rails "t", *Shellwords.split(arguments), allow_failure: true, **opts
Expand Down
Loading

0 comments on commit 613c20b

Please sign in to comment.