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