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

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

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

Как я могу выполнить задачи / код настройки базы данных rake test, не запуская 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

Примечание: в моем config / database.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 в .specjour / hooks.rb, поэтому, если есть какие-либо задачи rake или другой код, который мне нужно запустить, он может там работать.


person gerry3    schedule 06.05.2011    source источник


Ответы (6)


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

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

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

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

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

person edk750    schedule 07.05.2011
comment
Да, я запустил rake spec с --trace и попытался воспроизвести некоторые из его задач в моем хуке prepare specjour, но это еще не сработало. Я потенциально мог бы написать совершенно отдельную задачу по рейку, чтобы все было настроено, но это еще один шаг, которого я надеялся избежать. - person gerry3; 10.05.2011

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

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, потому что БД нельзя отбросить. Хитрая штука.

person leviathan    schedule 22.06.2012
comment
Более простое решение - просто запустить rake db:test:prepare. - person gerry3; 26.06.2012
comment
У меня нет проблем с запуском rake db:test:prepare с Postgres. Вы, должно быть, видите свою проблему по какой-то другой причине. - person gerry3; 12.07.2012
comment
Если db: test: prepare не работает, вы можете, по крайней мере, поместить команды в строку, чтобы сэкономить время ввода: RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load - person funwhilelost; 13.05.2014
comment
Похоже, что rake db:test:prepare устарел в Rails 4. - person markquezada; 25.05.2014
comment
Вы можете связать рейк-задачи следующим образом: bundle exec rake db:drop db:create db:schema:load RAILS_ENV=test - person davegson; 28.05.2015
comment
rake db:test:prepare все еще работает в rails 5 (и с PostgreSQL 10.3) - person gerry3; 03.03.2018

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

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

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

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

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

Редактировать

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

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

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

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

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

Хак 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
person Danyel    schedule 04.08.2013
comment
Аккуратный! Это очень полезно. - person odigity; 02.12.2013

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

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

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

person John Morales    schedule 20.05.2015

В подпружиненном приложении Rails 4 мой 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.

person Marius Butuc    schedule 07.07.2015

Я начал с удаления тестовой базы данных rake db:drop RAILS_ENV=test

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

введите psql в командной строке, а затем выполните приведенную ниже команду, чтобы создать тестовую базу данных, в которой используется учетная запись, отличная от вашей. CREATE DATABASE your_database_name OWNER your_db_owner;

затем запустите миграции в тестовой среде. rake db:migrate RAILS_ENV=test

person random_user_0891    schedule 15.06.2020