Skip to content

Instantly share code, notes, and snippets.

@hidakatsuya
Last active December 8, 2024 16:29
Show Gist options
  • Save hidakatsuya/ff3c06021ae8a851c917a67243a6d182 to your computer and use it in GitHub Desktop.
Save hidakatsuya/ff3c06021ae8a851c917a67243a6d182 to your computer and use it in GitHub Desktop.
How Fixtures Load Data in Rails Tests

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.

Preparation

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

Investigation

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:

1. a_test.rb

  1. Loading fixtures :users
    1. SQL: begin transaction
    2. SQL: DELETE FROM "users";: Clears the users table.
    3. INSERT INTO "users" ...: Inserts all data from users.yml.
    4. SQL: commit transaction
  2. Executing ATest
    1. SQL: begin transaction
    2. Executes test "A test".
    3. SQL: rollback transaction

2. b_test.rb

  1. Loading fixtures :projects
    1. SQL: begin transaction
    2. SQL: DELETE FROM "projects";: Clears the projects table.
    3. INSERT INTO "projects" ...: Inserts all data from projects.yml.
    4. SQL: commit transaction
  2. Executing BTest
    1. SQL: begin transaction
    2. Executes test "B test".
    3. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment