Как подготовить тестовые базы данных для тестов Rails rspec без запуска спецификации rake?


после значительного устранения неполадок я понял, что мне нужно запустить rake spec один раз (я могу прервать с помощью control-c), прежде чем я смогу запустить rspec напрямую (например, на подмножестве наших спецификаций). Мы бежим рельсы 3.0.7 и RSpec 2.5.0.

очевидно, что rake выполняет некоторые важные задачи настройки базы данных / код (у нас есть пользовательский код в Rakefile rails корневого уровня и, возможно, в других местах).

как я могу запустить rake test database setup tasks / code без запуска rake spec?

в дополнение к возможности запуска rspec на подмножестве файлов, я использую specjour чтобы распространить наши спецификации на несколько ядер (еще не удалось распространить их по локальной сети), но я вижу то же поведение, что и для запуска rspec напрямую: мне нужно запустить rake spec на каждой тестовой базе данных (предполагая два ядра) перед specjour работает:

rake spec TEST_ENV_NUMBER=1
control-c (after tests start)
rake spec TEST_ENV_NUMBER=2
control-c (after tests start)
specjour

Примечание: моя конфигурация / база данных.в формате YML есть эта запись для проверки (как правило, параллельно тестирование драгоценных камней):

test:
  adapter: postgresql
  encoding: unicode
  database: test<%=ENV['TEST_ENV_NUMBER']%>
  username: user
  password:

parallel_tests кажется, правильно настроить свои базы данных, но многие из наших спецификаций терпят неудачу.

Я должен также упомянуть, что работает specjour prepare вызывает Postgres для регистрации ошибок, которые он не может найти базы данных, но он создает их (без таблиц). При последующем запуске ошибки не регистрируются, но и таблицы не создаются. Вполне возможно, что вся моя проблема-это просто ошибка prepare, поэтому я сообщил об этом на github.

Я думаю, что я могу запустить произвольный код на каждой тестовой базе данных specjour, установив Specjour::Configuration.prepare in .specjour / крючки.rb, поэтому, если есть какие-либо задачи rake или другой код, который мне нужно запустить, он может работать там.

5 77

5 ответов:

У меня была аналогичная проблема с настройкой системы CI на работе, поэтому я постепенно разрабатывал систему для обработки этого. Возможно, это не лучшее решение, но оно работает для меня в моей ситуации, и я всегда ищу лучшие способы делать вещи.

У меня есть тестовая база данных, которую мне нужно было настроить, но также нужны были загруженные данные для наших тестов.

основные задачи устранения неполадок rake-это запустить rake с параметром --trace, чтобы увидеть, что происходит под капюшон. Когда я это сделал, я обнаружил, что запуск Rake spec сделал ряд вещей, которые я мог бы воспроизвести (или изменить по своему усмотрению) в пользовательской задаче rake.

вот пример того, что мы делаем.

desc "Setup test database - drops, loads schema, migrates and seeds the test db"
task :test_db_setup => [:pre_reqs] do
  Rails.env = ENV['RAILS_ENV'] = 'test'
  Rake::Task['db:drop'].invoke
  Rake::Task['db:create'].invoke
  result = capture_stdout { Rake::Task['db:schema:load'].invoke }
  File.open(File.join(ENV['CC_BUILD_ARTIFACTS'] || 'log', 'schema-load.log'), 'w') { |f| f.write(result) }
  Rake::Task['db:seed:load'].invoke
  ActiveRecord::Base.establish_connection
  Rake::Task['db:migrate'].invoke
end

Это только пример, и специфичный для нашей ситуации, поэтому вам нужно будет выяснить, что нужно сделать, чтобы получить настройку тестовой БД, но это довольно легко определить с помощью опции --trace rake.

кроме того, если вы обнаружите, что тестовая установка принимает слишком долго (как и в нашем случае), вы также можете сбросить базу данных .формат sql и иметь тестовую базу данных трубы его непосредственно в mysql для загрузки. Таким образом, мы экономим несколько минут от настройки тестовой БД. Я не показываю это здесь, потому что это существенно усложняет вещи-его нужно правильно генерировать, не становясь устаревшим и т. д.

HTH

Я бы рекомендовал удалить тестовую базу данных, а затем повторно создать ее и перенести:

bundle exec rake db:drop RAILS_ENV=test
bundle exec rake db:create RAILS_ENV=test
bundle exec rake db:schema:load RAILS_ENV=test

после этих шагов вы можете выполнить ваши спецификации:

bundle exec rspec spec

gerry3 отметил, что:

более простое решение-просто запустить rake db:test:prepare

однако, если вы используете PostgreSQL, это не будет работать, потому что загружается среда rails, которая открывает соединение с базой данных. Это вызывает prepare вызов сбой, потому что БД не может быть удален. Сложная вещь.

обеспеченные решения все требуют для того чтобы нагрузить окружающую среду рельсов, которая, в большинстве случаев, не пожеланное поведение должное к очень большим накладным расходам и очень малой скорости. DatabaseCleaner gem также довольно медленно, и это добавляет еще одну зависимость от вашего приложения.

после нескольких месяцев огорчения и досады благодаря причинам, приведенным выше, я, наконец, нашел следующее решение, чтобы быть именно то, что мне нужно. Это красиво, просто и быстро. В spec_helper.rb:

config.after :all do
  ActiveRecord::Base.subclasses.each(&:delete_all)
end

самая лучшая часть о это: он будет очищать только те таблицы, которые у вас есть эффективно задел (нетронутые модели не будут загружены и, следовательно, не появятся в subclasses, также причина, почему это не работает до тесты). Кроме того, он выполняется после тестов, поэтому (надеюсь) зеленые точки появятся сразу.

единственным недостатком этого является то, что если у вас есть грязная база данных перед запуском тестов, она не будет очищена. Но я сомневаюсь, что это серьезная проблема, так как тестовая база данных обычно не затрагивается внешними тестами.

Edit

видя, как этот ответ приобрел некоторую популярность, я хотел отредактировать его для полноты: если вы хотите очистить все таблицы, даже те, которые не трогал, Вы должны быть в состоянии сделать что-то вроде "хаки" ниже.

Hack 1-предварительная загрузка всех моделей для subclasses метод

оцените это перед вызовом subclasses:

Dir[Rails.root.join("app", "models", "**", "*.rb")].each(&method(:require))

обратите внимание, что это метод может занять некоторое время!

Hack 2-ручное усечение таблиц

ActiveRecord::Base.connection.tables.keep_if{ |x| x != 'schema_migrations' }

вы получите все имена таблиц, с которыми вы можете сделать что-то вроде:

case ActiveRecord::Base.configurations[Rails.env]["adapter"]
when /^mysql/, /^postgresql/
  ActiveRecord::Base.connection.execute("TRUNCATE #{table_name}")
when /^sqlite/
  ActiveRecord::Base.connection.execute("DELETE FROM #{table_name}")
  ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence where name='#{table_name}'")
end

похоже, что в Rails 4.1+ лучшим решением является просто добавить ActiveRecord::Migration.maintain_test_schema! в вашем rails_helper после require 'rspec/rails'.

т. е. вам больше не нужно беспокоиться о том, чтобы подготовить базу данных.

https://relishapp.com/rspec/rspec-rails/docs/upgrade#pending-migration-checks

в приложении spring-ified Rails 4, my bin/setup обычно дополняется, чтобы содержать

puts "\n== Preparing test database =="
system "RAILS_ENV=test bin/rake db:setup"

это очень похоже на Левиафан, плюс посев тестовой БД, как

rake db:setup# создайте базу данных, загрузите схему и инициализируйте с помощью исходных данных
(используйте
db:resetчтобы также сначала удалить базу данных)

как говорится в комментарии, если мы хотим удалить БД во-первых, rake db:reset делает именно это.

Я также считаю, что это обеспечивает больше обратной связи по сравнению с rake db:test:prepare.