Jak przygotować bazę danych testowych dla testów Rails rspec bez uruchamiania rake spec?

Po znaczącym rozwiązaniu problemu, zorientowałem się, że muszę uruchomić rake spec raz (mogę przerwać za pomocą control-c), zanim będę mógł uruchomić RSpec bezpośrednio (np. na podzbiorze naszych specyfikacji). Mamy Rails 3.0.7 i RSpec 2.5.0.

Oczywiście, rake uruchamia kilka ważnych zadań / kodu konfiguracji bazy danych (mamy niestandardowy kod w pliku Rakefile Rails poziomu głównego i ewentualnie w innych miejscach).

Jak mogę uruchomić zadania / kod testowy bazy danych rake bez uruchamiania rake spec?

Oprócz tego, że mogę uruchomić rspec na podzbiorze plików, używam specjour , aby rozłożyć nasze specyfikacje na wiele rdzeni (nie udało mi się jeszcze rozprowadzić ich po sieci LAN), ale widzę to samo zachowanie, jak w przypadku bezpośredniego uruchamiania rspec: muszę uruchomić rake spec na każdej testowej bazie danych (zakładając dwa rdzenie), zanim specjour zadziała:

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

Uwaga: moja konfiguracja / baza danych.yml ma ten wpis do testu (jak to jest powszechne dla równoległych testów "perełki"): {]}

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

Parallel_tests wydaje się poprawnie skonfigurować swoje bazy danych, ale wiele z naszych specyfikacji zawodzi.

Powinienem również wspomnieć, że uruchomienie specjour prepare powoduje, że Postgres rejestruje błędy, że nie może znaleźć baz danych, ale je tworzy (bez tabel). Przy kolejnym uruchomieniu nie są rejestrowane żadne błędy, ale również nie są tworzone tabele. Możliwe, że cały mój problem jest po prostu błędem w prepare, więc zgłosiłem go na GitHubie.

Myślę, że mogę uruchomić dowolny kod na każdym specjour test bazy danych poprzez ustawienie Specjour::Configuration.prepare w .specjour / hooks.rb, więc jeśli są jakieś zadania rake lub inny kod, który muszę uruchomić, może tam działać.

Author: gerry3, 2011-05-06

5 answers

Miałem podobny problem z konfiguracją systemu CI w pracy, więc stopniowo opracowałem system, który poradzi sobie z tym. Może nie jest to najlepsze rozwiązanie, ale działa na mnie w mojej sytuacji i zawsze szukam lepszych sposobów na robienie rzeczy.

Mam testową bazę danych, którą potrzebowałem konfiguracji, ale również potrzebowałem załadowanych danych, aby nasze testy działały.

Podstawy rozwiązywania zadań rake polega na uruchomieniu rake z opcją --trace, aby zobaczyć, co dzieje się pod maską. Kiedy ja czy to, odkryłem, że uruchomiony Rake spec zrobił wiele rzeczy ,które mogłem replikować (lub modyfikować, jak zobaczyłem, że pasuje) w niestandardowym zadaniu rake.

Oto przykład tego, co robimy.
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

To tylko przykład, specyficzny dla naszej sytuacji, więc musisz dowiedzieć się, co należy zrobić, aby uzyskać konfigurację test db, ale jest to dość łatwe do określenia za pomocą opcji --trace rake.

Dodatkowo, jeśli okaże się, że konfiguracja testu trwa zbyt długo (tak jak w naszym przypadku), możesz również wrzucić bazę danych do .format sql i niech testowa baza danych przeniesie go bezpośrednio do mysql, aby załadować. W ten sposób oszczędzamy kilka minut na konfiguracji testowej bazy danych. Nie pokazuję tego tutaj, bo to znacznie komplikuje sprawy . trzeba to odpowiednio wygenerować, nie starzejąc się itp.

HTH

 13
Author: edk750,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-07 16:55:00

Zalecałbym porzucenie testowej bazy danych, a następnie ponowne jej utworzenie i migrację:

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

Po tych krokach możesz uruchomić swoje specyfikacje:

bundle exec rspec spec

Gerry3 zauważył, że:

Prostszym rozwiązaniem jest po prostu uruchomić rake db:test:prepare

Jeśli jednak używasz PostgreSQL to nie zadziała, ponieważ środowisko rails zostanie załadowane, co otworzy połączenie z bazą danych. Powoduje to, że wywołanie prepare nie powiedzie się, ponieważ DB nie może zostać upuszczone. Trudna sprawa.

 139
Author: leviathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:14

Dostarczone rozwiązania wymagają załadunku środowiska szyn, co w większości przypadków nie jest pożądanym zachowaniem ze względu na bardzo duże obciążenie i bardzo niską prędkość. DatabaseCleaner gem jest również dość powolny, i dodaje kolejną zależność do aplikacji.

Po miesiącach niepokoju i irytacji z powodów vide supra, w końcu znalazłem następujące rozwiązanie, które jest dokładnie tym, czego potrzebuję. Jest ładny, prosty i szybki. W spec_helper.rb:

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

Najlepsze w tym jest to, że będzie tylko Wyczyść tabele, które skutecznie dotknąłeś (nietknięte modele nie zostaną załadowane i tym samym nie pojawią się w subclasses, również powód, dla którego to nie działa przed testami). Również, wykonuje po testach, więc (miejmy nadzieję) zielone kropki pojawią się od razu.

Jedynym minusem jest to, że jeśli masz brudną bazę danych przed uruchomieniem testów, nie zostanie ona wyczyszczona. Ale wątpię, że jest to poważny problem, ponieważ baza testowa zazwyczaj nie jest dotykana z testy zewnętrzne.

Edit

Ponieważ ta odpowiedź zyskała pewną popularność, chciałem ją edytować dla kompletności: jeśli chcesz wyczyścić wszystkie tabele, nawet te, które nie zostały dotknięte, powinieneś być w stanie zrobić coś takiego jak "hacki" poniżej.

Hack 1 - wstępne ładowanie wszystkich modeli dla metody subclasses

Oceń to przed wywołaniem subclasses:

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

Zauważ, że ta metoda może zająć trochę czasu!

Hack 2-ręczne obcinanie tabele

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

Dostaniesz wszystkie nazwy tabel, z tymi możesz zrobić coś takiego:

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
 14
Author: Danyel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-31 14:55:25

Wygląda na to, że w Rails 4.1+ najlepszym rozwiązaniem jest dodanie ActiveRecord::Migration.maintain_test_schema! do rails_helper po require 'rspec/rails'.

Nie musisz się już martwić o przygotowanie bazy danych.

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

 5
Author: John Morales,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-02 23:02:08

W aplikacji rails 4, Moje bin/setup jest zwykle rozszerzone o

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

Jest to bardzo podobne do odpowiedź Lewiatana, plus seeding test DB, jak

rake db:setup # Tworzenie bazy danych, ładowanie schematu i inicjalizacja za pomocą danych nasiennych
(użycie
db:reset aby najpierw upuścić bazę danych)

Jak wspomniano w komentarzu, jeśli chcemy najpierw zrzucić DB, rake db:reset właśnie to robi.

Uważam również, że to dostarcza więcej informacji zwrotnych w porównaniu do rake db:test:prepare.

 3
Author: Marius Butuc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:14