Skip to content

Instantly share code, notes, and snippets.

@arthurnn
Last active October 29, 2018 04:57
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arthurnn/ad5aa2b6811dfddaf94fa35aed84a73c to your computer and use it in GitHub Desktop.
Save arthurnn/ad5aa2b6811dfddaf94fa35aed84a73c to your computer and use it in GitHub Desktop.
Load ActiveRecord fixtures from a block instead of a yml file
require 'minitest/autorun'
require 'active_record'
ActiveRecord::Base.logger = Logger.new(STDOUT)
conn = { adapter: 'sqlite3', database: ':memory:' }
ActiveRecord::Base.establish_connection(conn)
class User < ActiveRecord::Base
connection.create_table :users, force: true do |t|
t.string :username
t.timestamps
end
end
class ExampleTest < ActiveSupport::TestCase
include ActiveRecord::TestFixtures
include GitHub::Fixtures
fixtures do
@user = User.create!(username: "dhh")
end
setup do
# make sure username is reset
assert_equal "dhh", @user.username
end
test "save!" do
@user.username = "arthurnn"
@user.save!
assert_equal "arthurnn", @user.username
end
test "update!" do
@user.update!(username: 'arthurnn2')
assert_equal 'arthurnn2', @user.username
end
end
require 'active_support/all'
module GitHub
module Fixtures
extend ActiveSupport::Concern
included do
include ActiveSupport::Callbacks
define_callbacks :fixtures
prepend BlockFixtures
class << self
prepend BlockFixtures::ClassMethods
end
end
module BlockFixtures
module ClassMethods
# Public: Declare fixtures for all tests in the test class.
#
# &block - Block that creates fixture data. The database will be rolled back
# to this state between tests.
#
# Returns nothing.
def fixtures(*args, &block)
set_callback(:fixtures, :before, *args, &block)
end
end
# When reloading the instance variables saved by the fixtures block,
# ActiveRecord::Fixtures will invoke a `find` method in that instance.
# This is a class that implements the `find` method, so we reload
# the persisted object into different test runs.
class InlineFixtureSet
def initialize(object)
@object = object
end
def model_class
@object.class
end
def find
if model_class.respond_to?(:find)
if model_class.respond_to?(:unscoped)
model_class.unscoped.where(:id => @object.id).first!
else
model_class.find(@object.id)
end
else
@object
end
rescue ActiveRecord::RecordNotFound
warn "Record #{@object.inspect} not found"
nil
end
end
# Private: Method called from ActiveRecord::Fixtures module.
# This method is reponsible for loading the fixtures into the database.
# And also to track the instance variables so the next run can load them.
# see https://github.com/rails/rails/blob/65b62f652ca564c3904e2d32d25e079090f3c78c/activerecord/lib/active_record/fixtures.rb#L894
def load_fixtures(*)
fixtures_loaded = {}
# before loading the fixtures we need to cleanup the database
enlist_fixture_connections.each do |conn|
conn.tables.each do |table|
conn.delete "DELETE FROM #{table}"
end
end
before = instance_variables
# Enable the instantiation of fixtures for the next runs,
# so we don't need to eval the fixtures block again.
self.class.use_instantiated_fixtures = true
run_callbacks :fixtures
(instance_variables - before).each do |ivar|
fixtures_loaded[ivar[1..-1]] = InlineFixtureSet.new(instance_variable_get(ivar))
end
{fixtures: fixtures_loaded}
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment