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
end
To 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]}"
end
Run 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 :users
SQL: begin transaction
SQL: DELETE FROM "users";
: Clears theusers
table.INSERT INTO "users" ...
: Inserts all data fromusers.yml
.SQL: commit transaction
- Executing
ATest
SQL: begin transaction
- Executes
test "A test"
. SQL: rollback transaction
- Loading
fixtures :projects
SQL: begin transaction
SQL: DELETE FROM "projects";
: Clears theprojects
table.INSERT INTO "projects" ...
: Inserts all data fromprojects.yml
.SQL: commit transaction
- Executing
BTest
SQL: 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.