Testing ActiveRecord Database Integration in will_paginate
This test connector provides a robust testing infrastructure for ActiveRecord integration within the will_paginate library. It establishes database connections, loads test schemas, and manages fixtures for comprehensive database testing scenarios.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
mislav/will_paginate
spec/finders/activerecord_test_connector.rb
require 'active_record'
require 'active_record/fixtures'
require 'stringio'
require 'erb'
require 'time'
require 'date'
require 'yaml'
# forward compatibility with Rails 7 (needed for time expressions within fixtures)
class Time
alias_method :to_fs, :to_s
end unless Time.new.respond_to?(:to_fs)
# monkeypatch needed for Ruby 3.1 & Rails 6.0
YAML.module_eval do
class << self
alias_method :_load_orig, :load
def load(yaml_str)
_load_orig(yaml_str, permitted_classes: [Symbol, Date, Time])
end
end
end if YAML.method(:load).parameters.include?([:key, :permitted_classes])
$query_count = 0
$query_sql = []
ignore_sql = /
^(
PRAGMA | SHOW\ (max_identifier_length|search_path) |
SELECT\ (currval|CAST|@@IDENTITY|@@ROWCOUNT) |
SHOW\ ((FULL\ )?FIELDS|TABLES)
)\b |
\bFROM\ (sqlite_master|pg_tables|pg_attribute)\b
/x
ActiveSupport::Notifications.subscribe(/^sql\./) do |*args|
payload = args.last
unless payload[:name] =~ /^Fixture/ or payload[:sql] =~ ignore_sql
$query_count += 1
$query_sql << payload[:sql]
end
end
module ActiverecordTestConnector
extend self
attr_accessor :connected
FIXTURES_PATH = File.expand_path('../../fixtures', __FILE__)
# Set our defaults
self.connected = false
def setup
unless self.connected
setup_connection
load_schema
add_load_path FIXTURES_PATH
self.connected = true
end
end
private
module Autoloader
def const_missing(name)
super
rescue NameError
file = File.join(FIXTURES_PATH, name.to_s.underscore)
if File.exist?("#{file}.rb")
require file
const_get(name)
else
raise $!
end
end
end
def add_load_path(path)
if ActiveSupport::Dependencies.respond_to?(:autoloader=)
Object.singleton_class.include Autoloader
else
dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
dep.autoload_paths.unshift path
end
end
def setup_connection
db = ENV['DB'].blank?? 'sqlite3' : ENV['DB']
erb = ERB.new(File.read(File.expand_path('../../database.yml', __FILE__)))
configurations = YAML.load(erb.result)
raise "no configuration for '#{db}'" unless configurations.key? db
configuration = configurations[db]
# ActiveRecord::Base.logger = Logger.new(STDOUT) if $0 == 'irb'
puts "using #{configuration['adapter']} adapter"
ActiveRecord::Base.configurations = { db => configuration }
ActiveRecord::Base.establish_connection(db.to_sym)
if ActiveRecord.respond_to?(:default_timezone=)
ActiveRecord.default_timezone = :utc
else
ActiveRecord::Base.default_timezone = :utc
end
end
def load_schema
begin
$stdout = StringIO.new
ActiveRecord::Migration.verbose = false
load File.join(FIXTURES_PATH, 'schema.rb')
ensure
$stdout = STDOUT
end
end
module FixtureSetup
def fixtures(*tables)
table_names = tables.map { |t| t.to_s }
fixtures = ActiveRecord::FixtureSet.create_fixtures(ActiverecordTestConnector::FIXTURES_PATH, table_names)
@@loaded_fixtures = {}
@@fixture_cache = {}
unless fixtures.nil?
fixtures.each { |f| @@loaded_fixtures[f.table_name] = f }
end
table_names.each do |table_name|
define_method(table_name) do |*names|
@@fixture_cache[table_name] ||= {}
instances = names.map do |name|
if @@loaded_fixtures[table_name][name.to_s]
@@fixture_cache[table_name][name] ||= @@loaded_fixtures[table_name][name.to_s].find
else
raise StandardError, "No fixture with name '#{name}' found for table '#{table_name}'"
end
end
instances.size == 1 ? instances.first : instances
end
end
end
end
end