Nice programing

레이크 스펙을 실행하지 않고 Rails rspec 테스트를 위해 테스트 데이터베이스를 준비하려면 어떻게해야합니까?

nicepro 2020. 10. 4. 13:21
반응형

레이크 스펙을 실행하지 않고 Rails rspec 테스트를 위해 테스트 데이터베이스를 준비하려면 어떻게해야합니까?


중요한 문제 해결 후, rake specrspec을 직접 실행하기 전에 (예 : 사양의 하위 집합에서) 한 번 실행해야한다는 것을 알게 되었습니다 (control-c로 중단 할 수 있음). 우리는 Rails 3.0.7과 RSpec 2.5.0을 실행하고 있습니다.

분명히, rake는 몇 가지 중요한 데이터베이스 설정 작업 / 코드를 실행하고 있습니다 (루트 레벨 레일 Rakefile 및 기타 위치에 사용자 지정 코드가 있음).

실행하지 않고 레이크 테스트 데이터베이스 설정 작업 / 코드를 rake spec어떻게 실행할 수 있습니까?

파일의 하위 집합에서 rspec을 실행할 수있는 것 외에도 specjour사용하여 사양을 여러 코어에 분산하고 있지만 (아직 LAN을 통해 분산하는 데 성공하지 못함) rspec을 실행하는 것과 동일한 동작을 봅니다. 직접 : rake specspecjour가 작동하기 전에 각 테스트 데이터베이스 (2 개의 코어 가정) 에서 실행해야 합니다.

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에는 테스트를위한 다음 항목이 있습니다 (병렬 테스트 gem의 경우 일반적 임).

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

parallel_tests 는 데이터베이스를 올바르게 설정 것처럼 보이지만 많은 사양이 실패합니다.

또한 실행 specjour prepare하면 Postgres가 데이터베이스를 찾을 수 없다는 오류를 기록하지만 테이블없이 생성 된다는 점도 언급해야합니다 . 후속 실행에서는 오류가 기록되지 않지만 테이블도 생성되지 않습니다. 내 전체 문제가 단순히에서 버그 prepare일 수 있으므로 github에보고했습니다.

Specjour::Configuration.prepare.specjour / hooks.rb 를 설정하여 각 specjour 테스트 데이터베이스에서 임의의 코드를 실행할 수 있다고 생각하므로 실행 해야하는 레이크 작업이나 다른 코드가 있으면 작동 할 수 있습니다.


직장에서 CI 시스템을 설정하는 데 비슷한 문제가 있었기 때문에 점차적으로이를 처리 할 시스템을 구축했습니다. 최선의 해결책은 아닐 수도 있지만 제 상황에서 저에게 효과적이며 항상 더 나은 방법을 찾고 있습니다.

설정이 필요한 테스트 데이터베이스가 있지만 테스트가 작동하려면로드 된 시드 데이터가 필요했습니다.

레이크 작업 문제 해결의 기본은 --trace 옵션으로 rake를 실행하여 내부에서 무슨 일이 일어나는지 확인하는 것입니다. 이 작업을 수행했을 때 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

이것은 예시 일 뿐이며 상황에 따라 다르므로 테스트 db 설정을 위해 수행해야 할 작업을 파악해야하지만 rake의 --trace 옵션을 사용하여 결정하는 것은 매우 쉽습니다.

또한 테스트 설정이 너무 오래 걸리는 경우 (우리의 경우처럼) 데이터베이스를 .sql 형식으로 덤프하고 테스트 데이터베이스에서 직접 mysql로 ​​파이프하여로드하도록 할 수 있습니다. 그런 식으로 테스트 db 설정에서 몇 분을 절약합니다. 여기에서는 그것이 상당히 복잡하기 때문에 여기에 표시하지 않습니다. 부실하지 않고 적절하게 생성되어야합니다.

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 환경이로드되어 데이터베이스 연결이 열리므로 작동하지 않습니다. 이로 인해 prepareDB를 삭제할 수 없기 때문에 호출이 실패합니다. 까다로운 것.


The provided solutions all require to load the Rails environment, which is, in most cases, not the desired behaviour due to very large overhead and very low speed. DatabaseCleaner gem is also rather slow, and it adds another dependency to your app.

After months of chagrin and vexation thanks to reasons vide supra, I have finally found the following solution to be exactly what I need. It's nice, simple and fast. In spec_helper.rb:

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

The best part about this is: It will only clear those tables that you have effectively touched (untouched Models will not be loaded and thus not appear in subclasses, also the reason why this doesn't work before tests). Also, it executes after the tests, so the (hopefully) green dots will appear right away.

The only downside to this is that if you have a dirty database before running tests, it will not be cleaned. But I doubt that is a major issue, since the test database is usually not touched from outside tests.

Edit

Seeing as this answer has gained some popularity, I wanted to edit it for completeness: if you want to clear all tables, even the ones not touched, you should be able to do something like the "hacks" below.

Hack 1 - pre-loading all models for subclasses method

Evaluate this before calling subclasses:

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

Note that this method may take some time!

Hack 2 - manually truncating the tables

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

will get you all table names, with those you can do something like:

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

It appears that in Rails 4.1+, the best solution is simply to add ActiveRecord::Migration.maintain_test_schema! in your rails_helper after require 'rspec/rails'.

i.e. you don't have to worry about having to prepare the database anymore.

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


In a spring-ified Rails 4 app, my bin/setup is usually augmented to contain

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

This is very similar to leviathan's answer, plus seeding the test DB, as

rake db:setup # Create the database, load the schema, and initialize with the seed data
(use
db:reset to also drop the database first)

As the comment mentions, if we want to drop the DB first, rake db:reset does just that.

I also find that this provides more feedback when compared to rake db:test:prepare.

참고URL : https://stackoverflow.com/questions/5916126/how-do-i-prepare-test-databases-for-rails-rspec-tests-without-running-rake-spe

반응형