Jak przygotować testowe bazy danych do testów rspec Rails bez uruchamiania specyfikacji rake?

83

Po znaczącym rozwiązywaniu problemów stwierdziłem, że muszę uruchomić rake specraz (mogę przerwać za pomocą control-c), zanim będę mógł bezpośrednio uruchomić rspec (np. Na podzbiorze naszych specyfikacji). Używamy Rails 3.0.7 i RSpec 2.5.0.

Najwyraźniej rake uruchamia kilka ważnych zadań / kodu konfiguracji bazy danych (mamy własny kod w pliku Rakefile na poziomie głównym i prawdopodobnie w innych miejscach).

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

Oprócz możliwości uruchamiania rspec na podzbiorze plików, używam specjour do rozprzestrzeniania naszych specyfikacji na wiele rdzeni (nie udało mi się jeszcze rozpowszechnić ich w sieci LAN), ale widzę to samo zachowanie, co przy uruchamianiu rspec bezpośrednio: muszę uruchomić rake specna każdej testowej bazie danych (zakładając dwa rdzenie) przed specjour dział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: mój plik config / database.yml ma ten wpis do testu (jak to jest typowe dla równoległych klejnotów testowych):

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

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

Powinienem również wspomnieć, że uruchomienie specjour preparepowoduje, ż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 także nie są tworzone żadne tabele. Możliwe, że cały mój problem jest po prostu błędem prepare, więc zgłosiłem to na githubie.

Myślę, że mogę uruchomić dowolny kod na każdej specjour testowej bazie danych, ustawiając Specjour::Configuration.preparew .specjour / hooks.rb, więc jeśli są jakieś zadania rake'u lub inny kod, który muszę uruchomić, może tam działać.

gerry3
źródło

Odpowiedzi:

14

Miałem podobny problem podczas konfigurowania systemu CI w pracy, więc stopniowo opracowałem system, który sobie z tym poradzi. Może to nie jest najlepsze rozwiązanie, ale sprawdza się w mojej sytuacji i zawsze szukam lepszych sposobów robienia rzeczy.

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

Podstawą rozwiązywania problemów z zadaniami rake jest uruchomienie rake z opcją --trace, aby zobaczyć, co się dzieje pod maską. Kiedy to zrobiłem, zauważyłem, że uruchomienie specyfikacji rake'u zrobiło wiele rzeczy, które mogłem odtworzyć (lub zmodyfikować według własnego uznania) 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 jest tylko przykład i specyficzny dla naszej sytuacji, więc musisz dowiedzieć się, co należy zrobić, aby uzyskać konfigurację testowej bazy danych, ale dość łatwo jest to określić 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ż zrzucić bazę danych do formatu .sql i przesłać testową bazę danych bezpośrednio do mysql w celu załadowania. W ten sposób oszczędzamy kilka minut na konfiguracji testowej bazy danych. Nie pokazuję tego tutaj, ponieważ znacznie komplikuje to sprawę - trzeba to poprawnie wygenerować bez starzenia itp.

HTH

edk750
źródło
Tak, uruchomiłem specyfikację rake z opcją --trace i próbowałem powielić niektóre jej zadania w moim haku specjour przygotowania, ale to jeszcze nie zadziałało. Potencjalnie mógłbym napisać całkowicie oddzielne zadanie rake, aby wszystko skonfigurować, ale to kolejny krok, którego miałem nadzieję uniknąć.
gerry3
170

Poleciłbym porzucić swoją testową bazę danych, a następnie utworzyć ją ponownie i przeprowadzić 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 uruchomienie rake db:test:prepare

Jednakże, jeśli używasz PostgreSQL, to nie zadziała, ponieważ środowisko rails jest ładowane, co otwiera połączenie z bazą danych. Powoduje prepareto niepowodzenie wywołania, ponieważ DB nie może zostać usunięty. Podstępna rzecz.

lewiatan
źródło
47
Prostszym rozwiązaniem jest po prostu uruchomienie rake db:test:prepare.
gerry3
7
Nie mam problemu rake db:test:preparez uruchomieniem Postgres. Musisz widzieć swój problem z innego powodu.
gerry3
Jeśli db: test: przygotowanie nie działa, możesz przynajmniej umieścić polecenia w RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load
tekście,
11
Wygląda na rake db:test:prepareto, że jest przestarzały w Railsach 4.
markquezada
8
Możesz łączyć zadania prowizji w następujący sposób:bundle exec rake db:drop db:create db:schema:load RAILS_ENV=test
davegson
14

Wszystkie dostarczone rozwiązania wymagają załadowania środowiska Rails, które w większości przypadków nie jest pożądane ze względu na bardzo duże obciążenie i bardzo małą prędkość. DatabaseCleanerKlejnot jest również dość powolny i dodaje kolejną zależność do Twojej aplikacji.

Po miesiącach zmartwień i irytacji z powodów vide powyżej, 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: wyczyści tylko te tabele, które skutecznie dotknąłeś (nietknięte modele nie zostaną załadowane, a zatem nie pojawią się w subclasses, a także powód, dla którego to nie działa przed testami). Ponadto jest wykonywany 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ę, czy jest to poważny problem, ponieważ testowa baza danych zwykle nie jest dotykana przez testy zewnętrzne.

Edytować

Widząc, że ta odpowiedź zyskała pewną popularność, chciałem ją zmienić, aby była kompletna: jeśli chcesz wyczyścić wszystkie tabele, nawet te nietknięte, powinieneś być w stanie zrobić coś w rodzaju „hacków” poniżej.

Hack 1 - wstępne ładowanie wszystkich modeli dla subclassesmetody

Oceń to przed telefonem subclasses:

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

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

Hack 2 - ręczne obcinanie tabel

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

dostaniesz wszystkie nazwy tabel, z tymi, które możesz zrobić na przykład:

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
Danyel
źródło
Schludny! Jest to całkiem przydatne.
jubileusz
3

W wiosennej aplikacji Rails 4 plik my bin/setupjest zwykle rozszerzany o zawartość

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

Jest to bardzo podobne do odpowiedzi Lewiatana , plus wysiew testowego DB, jak

rake db:setup # Utwórz bazę danych, załaduj schemat i zainicjuj z danymi początkowymi
(użyj
db:reset również, aby najpierw usunąć bazę danych)

Jak wspomniano w komentarzu, jeśli chcemy najpierw usunąć DB, rake db:resetzrób to.

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

Marius Butuc
źródło
0

Zacząłem od upuszczenia mojej testowej bazy danych rake db:drop RAILS_ENV=test

podczas próby utworzenia nowej testowej bazy danych napotkałem problem, ponieważ moje konto użytkownika różniło się od konta będącego właścicielem baz danych, więc zamiast tego utworzyłem bazę danych w PostgreSQL.

wpisz psqlwiersz polecenia, a następnie wykonaj poniższe czynności, aby utworzyć testową bazę danych korzystającą z konta innego niż Twoje. CREATE DATABASE your_database_name OWNER your_db_owner;

następnie uruchom migracje w środowisku testowym. rake db:migrate RAILS_ENV=test

random_user_0891
źródło