Note
This is the English version of the article available at https://hidakatsuya.dev/2024/12/09/how-the-fixtures-work.html.
This article explores how fixtures :users loads data in Rails tests. The investigation is based on the latest master branch of Redmine.
To analyze the behavior, two test files, ATest and BTest, are added:
https://github.com/hidakatsuya/redmine/commit/36c68804179eea117ac6eb1ea57ac4d2eb898ca4
# a_test.rb
require_relative '../test_helper'
class ATest < ActiveSupport::TestCase
fixtures :users
test "A test" do
puts "-- A test"
assert User.exists?(1)
end
end
# b_test.rb
require_relative '../test_helper'
class BTest < ActiveSupport::TestCase
fixtures :projects
test "B test" do
puts "-- B test"
assert User.exists?(1)
end
endTo observe SQL queries, subscribe to ActiveRecord SQL events in test_helper.rb:
# test_helper.rb
ActiveSupport::Notifications.subscribe('sql.active_record') do |name, start, finish, id, payload|
puts "SQL: #{payload[:sql]}"
endRun the tests:
$ bin/rails test test/unit/a_test.rb test/unit/b_test.rb
When tests are executed in the order a_test.rb -> b_test.rb, the database is manipulated as follows:
- Loading
fixtures :usersSQL: begin transactionSQL: DELETE FROM "users";: Clears theuserstable.INSERT INTO "users" ...: Inserts all data fromusers.yml.SQL: commit transaction
- Executing
ATestSQL: begin transaction- Executes
test "A test". SQL: rollback transaction
- Loading
fixtures :projectsSQL: begin transactionSQL: DELETE FROM "projects";: Clears theprojectstable.INSERT INTO "projects" ...: Inserts all data fromprojects.yml.SQL: commit transaction
- Executing
BTestSQL: begin transaction- Executes
test "B test". SQL: rollback transaction
After a_test.rb finishes, the data from users.yml remains in the database. Thus, b_test.rb executes with both users.yml and projects.yml data loaded.