Rails 3 + DataMapper-база данных не создана / уничтожена между тестами
Я попробую здесь, так как список рассылки для DM, к сожалению, не имеет большого вклада от других пользователей.
Я вполне уверен, что это не то, что мы должны делать вручную, но, возможно, я ошибаюсь. Я удалил ActiveRecord из своего проекта и начал создавать модели в DataMapper. Все это работает, но я хочу написать модульные тесты для моих моделей (и функциональные для моих контроллеров). Однако моя тестовая база данных не очищается между тестовыми запусками (это легко проверить с помощью теста). АР заботится об этом для вас, но, похоже, ребята из DM не учли это в своем проекте dm-rails. В отчаянной попытке стереть все с чистого листа, я сбросил все таблицы в моей тестовой базе данных. Теперь вместо того, чтобы мои модульные тесты терпели неудачу из-за загрязнения среды, они терпят неудачу из-за отсутствия схемы. Глядя на доступные мне задачи rake, я не могу восстановить свою тестовую базу данных, не очистив также свою базу данных разработки. Я начинаю сходить с ума и надеюсь, что парень DM + Пользователь Rails 3 может подтолкнуть меня в нужном направлении.В частности, когда я выполняю модульные тесты, все тестовые данные должны быть удалены между методами тестирования. Кроме того, если я внесу изменения в схему, я смогу запустить свои тесты, и они должны работать.
Я попытался поместить DataMapper.auto_migrate!
в setup
обратный вызов в моем test_helper.rb, но это, кажется, не создает схему (тесты все еще терпят неудачу из-за того, что таблицы не существуют, когда они пытаются вставить/выбрать записи).
Я видел https://github.com/bmabey/database_cleaner , но действительно ли нам нужно вводить внешнюю библиотеку в Rails только для того, чтобы сделать что-то, что DM, вероятно, уже имеет (казалось бы, недокументированную) поддержку? Это также не решает проблему воссоздания схемы.
1 ответ:
Ответ вернулся в список рассылки, что это в основном ситуация "Сделай сам", поэтому, чтобы избавить других от хлопот, если им тоже придется это делать:
Создайте a .файл rake в разделе lib / tasks, называется что-то вроде test_db_setup.грабли:
require File.dirname(__FILE__) + '/../../test/database_dumper' # Custom logic that runs before the test suite begins # This just clones the development database schema to the test database # Note that each test does a lightweight teardown of just truncating all tables namespace :db do namespace :test do desc "Reset the test database to match the development schema" task :prepare do Rake::Task['db:schema:clone'].invoke end end namespace :schema do desc "Literally dump the database schema into db/schema/**/*.sql" task :dump => :environment do DatabaseDumper.dump_schema(:directory => "#{Rails.root}/db/schema", :env => Rails.env) end desc "Clones the development schema into the test database" task :clone => [:dump, :environment] do DatabaseDumper.import_schema(:directory => "#{Rails.root}/db/schema", :env => "test") end end end task 'test:prepare' => 'db:test:prepare'
Здесь используется крюк
:test:prepare
, который предоставляет Rails, который запускается непосредственно перед началом набора тестов. Он копирует схему из вашей базы данных разработки в .sql-файлы в db / schema/ (по одному на таблицу / представление), затем он импортирует их .язык SQL файлы в тестовую базу данных.Вам понадобится служебный класс, который я написал для этой работы (в настоящее время он написан для MySQL >= 5.0.1. Вам придется изменить логику, если вам нужна другая база данных.
# Utility class for dumping and importing the database schema class DatabaseDumper def self.dump_schema(options = {}) options[:directory] ||= "#{Rails.root}/db/schema" options[:env] ||= Rails.env schema_dir = options[:directory] clean_sql_directory(schema_dir) Rails::DataMapper.configuration.repositories[options[:env]].each do |repository, config| repository_dir = "#{schema_dir}/#{repository}" adapter = DataMapper.setup(repository, config) perform_schema_dump(adapter, repository_dir) end end def self.import_schema(options = {}) options[:directory] ||= "#{Rails.root}/db/schema" options[:env] ||= "test" schema_dir = options[:directory] Rails::DataMapper.configuration.repositories[options[:env]].each do |repository, config| repository_dir = "#{schema_dir}/#{repository}" adapter = DataMapper.setup(repository, config) perform_schema_import(adapter, repository_dir) end end private def self.clean_sql_directory(path) Dir.mkdir(path) unless Dir.exists?(path) Dir.glob("#{path}/**/*.sql").each do |file| File.delete(file) end end def self.perform_schema_dump(adapter, path) Dir.mkdir(path) unless Dir.exists?(path) adapter.select("SHOW FULL TABLES").each do |row| name = row.values.first type = row.values.last sql_dir = "#{path}/#{directory_name_for_table_type(type)}" Dir.mkdir(sql_dir) unless Dir.exists?(sql_dir) schema_info = adapter.select("SHOW CREATE TABLE #{name}").first sql = schema_info.values.last f = File.open("#{sql_dir}/#{name}.sql", "w+") f << sql << "\n" f.close end end def self.directory_name_for_table_type(type) case type when "VIEW" "views" when "BASE TABLE" "tables" else raise "Unknown table type #{type}" end end def self.perform_schema_import(adapter, path) tables_dir = "#{path}/tables" views_dir = "#{path}/views" { "TABLE" => tables_dir, "VIEW" => views_dir }.each do |type, sql_dir| Dir.glob("#{sql_dir}/*.sql").each do |file| name = File.basename(file, ".sql") drop_sql = "DROP #{type} IF EXISTS `#{name}`" create_sql = File.open(file, "r").read adapter.execute(drop_sql) adapter.execute(create_sql) end end end end
Это также оставит .файлы sql в каталоге схемы, так что вы можете просматривать их, если вам нужна ссылка.
Теперь это будет только стереть вашу базу данных (установив новую схему), как тестовый пакет запускается. Он не будет стирать тесты между методами тестирования. Для что вы захотите использоватьDatabaseCleaner . Поместите его в свой test_helper.РБ:
require 'database_cleaner' DatabaseCleaner.strategy = :truncation, {:except => %w(auctionindexview helpindexview)} class ActiveSupport::TestCase setup :setup_database teardown :clean_database private def setup_database DatabaseCleaner.start end def clean_database DatabaseCleaner.clean end end
Теперь ты должен быть готов идти. Ваша схема будет обновлена, когда вы начнете выполнять тесты, у вас будет копия вашего SQL в каталоге db/schema, и ваши данные будут стерты между методами тестирования. Слово предупреждения, если вас привлекает транзакционная стратегия DatabaseCleaner... это редко безопасная стратегия для использования в MySQL, так как ни один из типов таблиц MySQL в настоящее время не поддерживает вложенные транзакции, так что ваша логика приложения, скорее всего, сломает разрыв. Усечение по-прежнему быстро и гораздо безопаснее.