Introducs `TestFixtures#fixture_paths`.

Multiple fixture paths can now be specified using the `#fixture_paths` accessor.
This commit is contained in:
Andrew Novoselac 2023-03-13 15:06:31 -04:00
parent fdceee8d78
commit 6902cbce1b
14 changed files with 97 additions and 49 deletions

View File

@ -14,10 +14,10 @@ require "webmock/minitest"
require "rails/test_unit/reporter" require "rails/test_unit/reporter"
Rails::TestUnitReporter.executable = "bin/test" Rails::TestUnitReporter.executable = "bin/test"
if ActiveSupport::TestCase.respond_to?(:fixture_path=) if ActiveSupport::TestCase.respond_to?(:fixture_paths=)
ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)]
ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path ActionDispatch::IntegrationTest.fixture_paths = ActiveSupport::TestCase.fixture_paths
ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files"
ActiveSupport::TestCase.fixtures :all ActiveSupport::TestCase.fixtures :all
end end

View File

@ -6,7 +6,10 @@ require "active_support/json/decoding"
require "rails/engine" require "rails/engine"
class TestCaseTest < ActionController::TestCase class TestCaseTest < ActionController::TestCase
def self.fixture_path; end def self.fixture_paths
[]
end
self.file_fixture_path = File.expand_path("../fixtures/multipart", __dir__) self.file_fixture_path = File.expand_path("../fixtures/multipart", __dir__)
class TestController < ActionController::Base class TestController < ActionController::Base
@ -931,14 +934,14 @@ class TestCaseTest < ActionController::TestCase
assert_equal "45142", @response.body assert_equal "45142", @response.body
end end
def test_fixture_file_upload_ignores_fixture_path_given_full_path def test_fixture_file_upload_ignores_fixture_paths_given_full_path
TestCaseTest.stub :fixture_path, __dir__ do TestCaseTest.stub :fixture_paths, __dir__ do
uploaded_file = fixture_file_upload("#{FILES_DIR}/ruby_on_rails.jpg", "image/jpeg") uploaded_file = fixture_file_upload("#{FILES_DIR}/ruby_on_rails.jpg", "image/jpeg")
assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read
end end
end end
def test_fixture_file_upload_ignores_nil_fixture_path def test_fixture_file_upload_ignores_empty_fixture_paths
uploaded_file = fixture_file_upload("#{FILES_DIR}/ruby_on_rails.jpg", "image/jpeg") uploaded_file = fixture_file_upload("#{FILES_DIR}/ruby_on_rails.jpg", "image/jpeg")
assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read assert_equal File.open("#{FILES_DIR}/ruby_on_rails.jpg", READ_PLAIN).read, uploaded_file.read
end end

View File

@ -16,10 +16,10 @@ Rails::TestUnitReporter.executable = "bin/test"
I18n.enforce_available_locales = false I18n.enforce_available_locales = false
# Load fixtures from the engine # Load fixtures from the engine
if ActiveSupport::TestCase.respond_to?(:fixture_path=) if ActiveSupport::TestCase.respond_to?(:fixture_paths=)
ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)]
ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path ActionDispatch::IntegrationTest.fixture_paths = ActiveSupport::TestCase.fixture_paths
ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files"
ActiveSupport::TestCase.fixtures :all ActiveSupport::TestCase.fixtures :all
end end

View File

@ -94,7 +94,7 @@ class ActiveRecordTestCase < ActionController::TestCase
# Set our fixture path # Set our fixture path
if ActiveRecordTestConnector.able_to_connect if ActiveRecordTestConnector.able_to_connect
self.fixture_path = [FIXTURE_LOAD_PATH] self.fixture_paths = [FIXTURE_LOAD_PATH]
self.use_transactional_tests = false self.use_transactional_tests = false
end end

View File

@ -1,3 +1,18 @@
* Introduce `TestFixtures#fixture_paths`.
Multiple fixture paths can now be specified using the `#fixture_paths` accessor.
Apps will continue to have `test/fixtures` as their one fixture path by default,
but additional fixture paths can be specified.
```ruby
ActiveSupport::TestCase.fixture_paths << "component1/test/fixtures"
ActiveSupport::TestCase.fixture_paths << "component2/test/fixtures"
```
`TestFixtures#fixture_path` is now deprecated.
*Andrew Novoselac*
* Respect `foreign_type` option to `delegated_type` for `{role}_class` method. * Respect `foreign_type` option to `delegated_type` for `{role}_class` method.
Usage of `delegated_type` with non-conventional `{role}_type` column names can now be specified with `foreign_type` option. Usage of `delegated_type` with non-conventional `{role}_type` column names can now be specified with `foreign_type` option.

View File

@ -17,8 +17,8 @@ module ActiveRecord
# \Fixtures are a way of organizing data that you want to test against; in short, sample data. # \Fixtures are a way of organizing data that you want to test against; in short, sample data.
# #
# They are stored in YAML files, one file per model, which are placed in the directory # They are stored in YAML files, one file per model, which are placed in the directories
# appointed by <tt>ActiveSupport::TestCase.fixture_path=(path)</tt> (this is automatically # appointed by <tt>ActiveSupport::TestCase.fixture_paths=(path)</tt> (this is automatically
# configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>). # configured for Rails, so you can just put your files in <tt><your-rails-app>/test/fixtures/</tt>).
# The fixture file ends with the +.yml+ file extension, for example: # The fixture file ends with the +.yml+ file extension, for example:
# <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>). # <tt><your-rails-app>/test/fixtures/web_sites.yml</tt>).
@ -552,7 +552,7 @@ module ActiveRecord
end end
end end
def create_fixtures(fixtures_directory, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block) def create_fixtures(fixtures_directories, fixture_set_names, class_names = {}, config = ActiveRecord::Base, &block)
fixture_set_names = Array(fixture_set_names).map(&:to_s) fixture_set_names = Array(fixture_set_names).map(&:to_s)
class_names = ClassCache.new class_names, config class_names = ClassCache.new class_names, config
@ -565,7 +565,7 @@ module ActiveRecord
if fixture_files_to_read.any? if fixture_files_to_read.any?
fixtures_map = read_and_insert( fixtures_map = read_and_insert(
fixtures_directory, Array(fixtures_directories),
fixture_files_to_read, fixture_files_to_read,
class_names, class_names,
connection, connection,
@ -591,15 +591,16 @@ module ActiveRecord
end end
private private
def read_and_insert(fixtures_directory, fixture_files, class_names, connection) # :nodoc: def read_and_insert(fixtures_directories, fixture_files, class_names, connection) # :nodoc:
fixtures_map = {} fixtures_map = {}
directory_glob = "{#{fixtures_directories.join(",")}}"
fixture_sets = fixture_files.map do |fixture_set_name| fixture_sets = fixture_files.map do |fixture_set_name|
klass = class_names[fixture_set_name] klass = class_names[fixture_set_name]
fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new fixtures_map[fixture_set_name] = new( # ActiveRecord::FixtureSet.new
nil, nil,
fixture_set_name, fixture_set_name,
klass, klass,
::File.join(fixtures_directory, fixture_set_name) ::File.join(directory_glob, fixture_set_name)
) )
end end
update_all_loaded_fixtures(fixtures_map) update_all_loaded_fixtures(fixtures_map)
@ -715,10 +716,13 @@ module ActiveRecord
# Loads the fixtures from the YAML file at +path+. # Loads the fixtures from the YAML file at +path+.
# If the file sets the +model_class+ and current instance value is not set, # If the file sets the +model_class+ and current instance value is not set,
# it uses the file value. # it uses the file value.
def read_fixture_files(path) def read_fixture_files(path)
yaml_files = Dir["#{path}/{**,*}/*.yml"].select { |f| yaml_files = Dir["#{path}{.yml,/{**,*}/*.yml}"].select { |f|
::File.file?(f) ::File.file?(f)
} + [yaml_file_path(path)] }
raise ArgumentError, "No fixture files found for #{@name}" if yaml_files.empty?
yaml_files.each_with_object({}) do |file, fixtures| yaml_files.each_with_object({}) do |file, fixtures|
FixtureSet::File.open(file) do |fh| FixtureSet::File.open(file) do |fh|
@ -730,10 +734,6 @@ module ActiveRecord
end end
end end
end end
def yaml_file_path(path)
"#{path}.yml"
end
end end
class Fixture # :nodoc: class Fixture # :nodoc:

View File

@ -17,7 +17,7 @@ module ActiveRecord
end end
included do included do
class_attribute :fixture_path, instance_writer: false class_attribute :fixture_paths, instance_writer: false, default: []
class_attribute :fixture_table_names, default: [] class_attribute :fixture_table_names, default: []
class_attribute :fixture_class_names, default: {} class_attribute :fixture_class_names, default: {}
class_attribute :use_transactional_tests, default: true class_attribute :use_transactional_tests, default: true
@ -40,12 +40,24 @@ module ActiveRecord
self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys) self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
end end
def fixture_path
ActiveRecord.deprecator.warn("TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2. Use #fixture_paths instead.")
fixture_paths
end
def fixture_path=(path)
ActiveRecord.deprecator.warn("TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2. Use #fixture_paths instead.")
self.fixture_paths = Array(path)
end
def fixtures(*fixture_set_names) def fixtures(*fixture_set_names)
if fixture_set_names.first == :all if fixture_set_names.first == :all
raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank? raise StandardError, "No fixture path found. Please set `#{self}.fixture_paths`." if fixture_paths.blank?
fixture_set_names = Dir[::File.join(fixture_path, "{**,*}/*.{yml}")].uniq fixture_set_names = fixture_paths.flat_map do |path|
fixture_set_names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path names = Dir[::File.join(path, "{**,*}/*.{yml}")].uniq
fixture_set_names.map! { |f| f[fixture_path.to_s.size..-5].delete_prefix("/") } names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path
names.map! { |f| f[path.to_s.size..-5].delete_prefix("/") }
end.uniq
else else
fixture_set_names = fixture_set_names.flatten.map(&:to_s) fixture_set_names = fixture_set_names.flatten.map(&:to_s)
end end
@ -81,6 +93,11 @@ module ActiveRecord
end end
end end
def fixture_path
ActiveRecord.deprecator.warn("TestFixtures#fixture_path is deprecated and will be removed in Rails 7.2. Use #fixture_paths instead.")
fixture_paths
end
def run_in_transaction? def run_in_transaction?
use_transactional_tests && use_transactional_tests &&
!self.class.uses_transaction?(name) !self.class.uses_transaction?(name)
@ -215,7 +232,7 @@ module ActiveRecord
end end
def load_fixtures(config) def load_fixtures(config)
ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config).index_by(&:name) ActiveRecord::FixtureSet.create_fixtures(fixture_paths, fixture_table_names, fixture_class_names, config).index_by(&:name)
end end
def instantiate_fixtures def instantiate_fixtures

View File

@ -482,7 +482,7 @@ class FixturesTest < ActiveRecord::TestCase
# Ensure that this file never exists # Ensure that this file never exists
assert_empty Dir[nonexistent_fixture_path + "*"] assert_empty Dir[nonexistent_fixture_path + "*"]
assert_raise(Errno::ENOENT) do assert_raise(ArgumentError) do
ActiveRecord::FixtureSet.new(nil, "companies", Company, nonexistent_fixture_path) ActiveRecord::FixtureSet.new(nil, "companies", Company, nonexistent_fixture_path)
end end
end end
@ -1125,7 +1125,7 @@ end
class LoadAllFixturesTest < ActiveRecord::TestCase class LoadAllFixturesTest < ActiveRecord::TestCase
def test_all_there def test_all_there
self.class.fixture_path = FIXTURES_ROOT + "/all" self.class.fixture_paths = [FIXTURES_ROOT + "/all"]
self.class.fixtures :all self.class.fixtures :all
if File.symlink? FIXTURES_ROOT + "/all/admin" if File.symlink? FIXTURES_ROOT + "/all/admin"
@ -1136,9 +1136,22 @@ class LoadAllFixturesTest < ActiveRecord::TestCase
end end
end end
class LoadAllFixturesWithArrayTest < ActiveRecord::TestCase
def test_all_there
self.class.fixture_paths = [FIXTURES_ROOT + "/all", FIXTURES_ROOT + "/categories"]
self.class.fixtures :all
if File.symlink? FIXTURES_ROOT + "/all/admin"
assert_equal %w(admin/accounts admin/users developers namespaced/accounts people special_categories subsubdir/arbitrary_filename tasks), fixture_table_names.sort
end
ensure
ActiveRecord::FixtureSet.reset_cache
end
end
class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase class LoadAllFixturesWithPathnameTest < ActiveRecord::TestCase
def test_all_there def test_all_there
self.class.fixture_path = Pathname.new(FIXTURES_ROOT).join("all") self.class.fixture_paths = [Pathname.new(FIXTURES_ROOT).join("all")]
self.class.fixtures :all self.class.fixtures :all
if File.symlink? FIXTURES_ROOT + "/all/admin" if File.symlink? FIXTURES_ROOT + "/all/admin"
@ -1482,13 +1495,13 @@ class NilFixturePathTest < ActiveRecord::TestCase
error = assert_raises(StandardError) do error = assert_raises(StandardError) do
TestCase = Class.new(ActiveRecord::TestCase) TestCase = Class.new(ActiveRecord::TestCase)
TestCase.class_eval do TestCase.class_eval do
self.fixture_path = nil self.fixture_paths = nil
fixtures :all fixtures :all
end end
end end
assert_equal <<~MSG.squish, error.message assert_equal <<~MSG.squish, error.message
No fixture path found. No fixture path found.
Please set `NilFixturePathTest::TestCase.fixture_path`. Please set `NilFixturePathTest::TestCase.fixture_paths`.
MSG MSG
end end
end end
@ -1499,7 +1512,7 @@ class FileFixtureConflictTest < ActiveRecord::TestCase
end end
test "ignores file fixtures" do test "ignores file fixtures" do
self.class.fixture_path = FIXTURES_ROOT + "/all" self.class.fixture_paths = [FIXTURES_ROOT + "/all"]
self.class.fixtures :all self.class.fixtures :all
assert_equal %w(developers namespaced/accounts people tasks), fixture_table_names.sort assert_equal %w(developers namespaced/accounts people tasks), fixture_table_names.sort

View File

@ -27,12 +27,12 @@ module ActiveRecord
include LoadSchemaHelper include LoadSchemaHelper
extend LoadSchemaHelper extend LoadSchemaHelper
self.fixture_path = FIXTURES_ROOT self.fixture_paths = [FIXTURES_ROOT]
self.use_instantiated_fixtures = false self.use_instantiated_fixtures = false
self.use_transactional_tests = true self.use_transactional_tests = true
def create_fixtures(*fixture_set_names, &block) def create_fixtures(*fixture_set_names, &block)
ActiveRecord::FixtureSet.create_fixtures(ActiveRecord::TestCase.fixture_path, fixture_set_names, fixture_class_names, &block) ActiveRecord::FixtureSet.create_fixtures(ActiveRecord::TestCase.fixture_paths, fixture_set_names, fixture_class_names, &block)
end end
def teardown def teardown

View File

@ -32,7 +32,7 @@ class TestFixturesTest < ActiveRecord::TestCase
klass = Class.new(Minitest::Test) do klass = Class.new(Minitest::Test) do
include ActiveRecord::TestFixtures include ActiveRecord::TestFixtures
self.fixture_path = tmp_dir self.fixture_paths = [tmp_dir]
self.use_transactional_tests = true self.use_transactional_tests = true
fixtures :all fixtures :all

View File

@ -25,7 +25,7 @@ class ActiveSupport::TestCase
include ActiveRecord::TestFixtures include ActiveRecord::TestFixtures
self.fixture_path = File.expand_path("fixtures", __dir__) self.fixture_paths = [File.expand_path("fixtures", __dir__)]
setup do setup do
ActiveStorage::Current.url_options = { protocol: "https://", host: "example.com", port: nil } ActiveStorage::Current.url_options = { protocol: "https://", host: "example.com", port: nil }

View File

@ -12,10 +12,10 @@ require "rails/test_help"
<% unless options[:skip_active_record] -%> <% unless options[:skip_active_record] -%>
# Load fixtures from the engine # Load fixtures from the engine
if ActiveSupport::TestCase.respond_to?(:fixture_path=) if ActiveSupport::TestCase.respond_to?(:fixture_paths=)
ActiveSupport::TestCase.fixture_path = File.expand_path("fixtures", __dir__) ActiveSupport::TestCase.fixture_paths = [File.expand_path("fixtures", __dir__)]
ActionDispatch::IntegrationTest.fixture_path = ActiveSupport::TestCase.fixture_path ActionDispatch::IntegrationTest.fixture_paths = ActiveSupport::TestCase.fixture_paths
ActiveSupport::TestCase.file_fixture_path = ActiveSupport::TestCase.fixture_path + "/files" ActiveSupport::TestCase.file_fixture_path = File.expand_path("fixtures", __dir__) + "/files"
ActiveSupport::TestCase.fixtures :all ActiveSupport::TestCase.fixtures :all
end end
<% end -%> <% end -%>

View File

@ -24,12 +24,12 @@ if defined?(ActiveRecord::Base)
include ActiveRecord::TestDatabases include ActiveRecord::TestDatabases
include ActiveRecord::TestFixtures include ActiveRecord::TestFixtures
self.fixture_path = "#{Rails.root}/test/fixtures/" self.fixture_paths << "#{Rails.root}/test/fixtures/"
self.file_fixture_path = fixture_path + "files" self.file_fixture_path = "#{Rails.root}/test/fixtures/files"
end end
ActiveSupport.on_load(:action_dispatch_integration_test) do ActiveSupport.on_load(:action_dispatch_integration_test) do
self.fixture_path = ActiveSupport::TestCase.fixture_path self.fixture_paths += ActiveSupport::TestCase.fixture_paths
end end
else else
ActiveSupport.on_load(:active_support_test_case) do ActiveSupport.on_load(:active_support_test_case) do

View File

@ -373,7 +373,7 @@ class PluginGeneratorTest < Rails::Generators::TestCase
assert_file "test/test_helper.rb" do |content| assert_file "test/test_helper.rb" do |content|
assert_match(/ActiveRecord::Migrator\.migrations_paths.+\.\.\/test\/dummy\/db\/migrate/, content) assert_match(/ActiveRecord::Migrator\.migrations_paths.+\.\.\/test\/dummy\/db\/migrate/, content)
assert_match(/ActiveRecord::Migrator\.migrations_paths.+<<.+\.\.\/db\/migrate/, content) assert_match(/ActiveRecord::Migrator\.migrations_paths.+<<.+\.\.\/db\/migrate/, content)
assert_match(/ActionDispatch::IntegrationTest\.fixture_path = ActiveSupport::TestCase\.fixture_pat/, content) assert_match(/ActionDispatch::IntegrationTest\.fixture_paths = ActiveSupport::TestCase\.fixture_pat/, content)
assert_no_match(/Rails::TestUnitReporter\.executable = "bin\/test"/, content) assert_no_match(/Rails::TestUnitReporter\.executable = "bin\/test"/, content)
end end
assert_no_file "bin/test" assert_no_file "bin/test"