Làm cách nào để chuẩn bị (các) cơ sở dữ liệu thử nghiệm cho các thử nghiệm Rails rspec mà không cần chạy thông số rake?


83

Sau khi khắc phục sự cố đáng kể, tôi phát hiện ra rằng tôi cần phải chạy rake specmột lần (tôi có thể hủy bằng control-c) trước khi có thể chạy trực tiếp rspec (ví dụ: trên một tập hợp con các thông số kỹ thuật của chúng tôi). Chúng tôi đang chạy Rails 3.0.7 và RSpec 2.5.0.

Rõ ràng, rake đang chạy một số tác vụ / mã thiết lập cơ sở dữ liệu quan trọng (chúng tôi có mã tùy chỉnh trong Rakefile cấp gốc và có thể là những nơi khác).

Làm cách nào để chạy các tác vụ / mã thiết lập cơ sở dữ liệu kiểm tra rake mà không chạy rake spec?

Ngoài việc có thể chạy rspec trên một tập hợp con của các tệp, tôi đang sử dụng specjour để truyền thông số kỹ thuật của chúng tôi trên nhiều lõi (chưa thành công với việc lan truyền chúng trên mạng LAN), nhưng tôi thấy hành vi tương tự như khi chạy rspec trực tiếp: Tôi cần chạy rake spectrên từng cơ sở dữ liệu thử nghiệm (giả sử hai lõi) trước khi specjour hoạt động:

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

Lưu ý: config / database.yml của tôi có mục này để thử nghiệm (như thường thấy đối với các gem thử nghiệm song song):

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

llel_tests dường như thiết lập cơ sở dữ liệu của nó một cách chính xác, nhưng nhiều thông số kỹ thuật của chúng tôi không thành công.

Tôi cũng nên đề cập rằng việc chạy specjour preparekhiến Postgres ghi lỗi mà nó không thể tìm thấy cơ sở dữ liệu, nhưng nó tạo ra chúng (không có bảng). Trong lần chạy tiếp theo, không có lỗi nào được ghi lại, nhưng cũng không có bảng nào được tạo. Có thể toàn bộ vấn đề của tôi chỉ đơn giản là một lỗi prepare, vì vậy tôi đã báo cáo nó trên github.

Tôi nghĩ rằng tôi có thể chạy mã tùy ý trên mỗi cơ sở dữ liệu thử nghiệm specjour bằng cách đặt Specjour::Configuration.preparetrong .specjour / hooks.rb, vì vậy nếu có bất kỳ tác vụ rake hoặc mã nào khác mà tôi cần chạy, nó có thể hoạt động ở đó.

Câu trả lời:


14

Tôi đã gặp vấn đề tương tự khi thiết lập hệ thống CI tại nơi làm việc, vì vậy tôi đã dần dần thiết lập một hệ thống để xử lý vấn đề này. Nó có thể không phải là giải pháp tốt nhất, nhưng nó phù hợp với tôi trong hoàn cảnh của tôi và tôi luôn tìm kiếm những cách tốt hơn để làm mọi việc.

Tôi có một cơ sở dữ liệu thử nghiệm mà tôi cần thiết lập, nhưng cũng cần tải dữ liệu hạt giống để các thử nghiệm của chúng tôi hoạt động.

Cơ bản của việc khắc phục sự cố các tác vụ rake là chạy rake với tùy chọn --trace để xem những gì đang xảy ra dưới mui xe. Khi tôi làm điều này, tôi thấy rằng việc chạy thông số kỹ thuật rake đã thực hiện một số thứ mà tôi có thể sao chép (hoặc sửa đổi khi tôi thấy phù hợp) trong một tác vụ rake tùy chỉnh.

Đây là một ví dụ về những gì chúng tôi làm.

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

Đây chỉ là một ví dụ và cụ thể cho tình huống của chúng tôi, vì vậy bạn sẽ cần phải tìm ra những gì cần phải làm để thiết lập db thử nghiệm của mình, nhưng khá dễ dàng để xác định bằng cách sử dụng tùy chọn --trace của rake.

Ngoài ra, nếu bạn thấy quá trình thiết lập thử nghiệm mất quá nhiều thời gian (như trong trường hợp của chúng tôi), bạn cũng có thể kết xuất cơ sở dữ liệu sang định dạng .sql và đặt cơ sở dữ liệu thử nghiệm chuyển nó trực tiếp vào mysql để tải. Chúng tôi tiết kiệm vài phút khi thiết lập db thử nghiệm theo cách đó. Tôi không cho thấy điều đó ở đây vì nó làm phức tạp mọi thứ về cơ bản - nó cần được tạo đúng cách mà không bị cũ, v.v.

HTH


Có, tôi đã chạy đặc tả rake với --trace và cố gắng sao chép một số nhiệm vụ của nó trong hook specjour chuẩn bị của tôi, nhưng nó vẫn chưa hoạt động. Tôi có khả năng viết một nhiệm vụ cào hoàn toàn riêng biệt để thiết lập mọi thứ, nhưng đó là một bước khác mà tôi hy vọng sẽ tránh được.
gerry 3

169

Tôi khuyên bạn nên bỏ cơ sở dữ liệu thử nghiệm của mình, sau đó tạo lại nó và di chuyển:

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

Sau các bước này, bạn có thể chạy thông số kỹ thuật của mình:

bundle exec rspec spec

gerry3 lưu ý rằng:

Một giải pháp đơn giản hơn là chỉ cần chạy rake db:test:prepare

Tuy nhiên, nếu bạn đang sử dụng PostgreSQL, điều này sẽ không hoạt động vì môi trường rails được tải, điều này sẽ mở ra một kết nối cơ sở dữ liệu. Điều này làm cho preparecuộc gọi không thành công, vì không thể bỏ DB. Đồ láu cá.


47
Một giải pháp đơn giản hơn là chỉ cần chạy rake db:test:prepare.
gerry

7
Tôi không gặp vấn đề gì khi chạy rake db:test:preparevới Postgres. Bạn phải thấy sự cố của mình vì một số lý do khác.
gerry 3

Nếu db: test: chuẩn bị không hoạt động, ít nhất bạn có thể đặt các lệnh nội tuyến để tiết kiệm một số thao tác nhập:RAILS_ENV=test bundle exec rake db:drop db:create db:schema:load
funwhilelost

11
Có vẻ như rake db:test:preparekhông được dùng nữa trong Rails 4.
markquezada

8
Bạn có thể chuỗi các nhiệm vụ rake như thế này:bundle exec rake db:drop db:create db:schema:load RAILS_ENV=test
davegson

14

Các giải pháp được cung cấp đều yêu cầu tải môi trường Rails, trong hầu hết các trường hợp, không phải là hành vi mong muốn do chi phí rất lớn và tốc độ rất thấp. DatabaseCleanergem cũng khá chậm và nó thêm một phần phụ thuộc khác vào ứng dụng của bạn.

Sau nhiều tháng thất vọng và bực bội vì những lý do vide supra, cuối cùng tôi đã tìm ra giải pháp sau đây chính là điều tôi cần. Nó đẹp, đơn giản và nhanh chóng. Trong spec_helper.rb:

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

Phần tốt nhất về điều này là: Nó sẽ chỉ xóa những bảng mà bạn đã chạm vào hiệu quả (Mô hình chưa được chạm sẽ không được tải và do đó không xuất hiện trong đó subclasses, cũng là lý do tại sao điều này không hoạt động trước khi kiểm tra). Ngoài ra, nó thực hiện sau các bài kiểm tra, vì vậy (hy vọng) các chấm màu xanh lá cây sẽ xuất hiện ngay lập tức.

Nhược điểm duy nhất của điều này là nếu bạn có một cơ sở dữ liệu bẩn trước khi chạy thử nghiệm, nó sẽ không được làm sạch. Nhưng tôi nghi ngờ đó là một vấn đề lớn, vì cơ sở dữ liệu thử nghiệm thường không được chạm vào từ các thử nghiệm bên ngoài.

Biên tập

Thấy rằng câu trả lời này đã trở nên phổ biến nhất định, tôi muốn chỉnh sửa nó cho hoàn chỉnh: nếu bạn muốn xóa tất cả các bảng, ngay cả những bảng không được chạm vào, bạn có thể làm một cái gì đó như "hack" bên dưới.

Hack 1 - tải trước tất cả các mô hình cho subclassesphương pháp

Đánh giá điều này trước khi gọi subclasses:

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

Lưu ý rằng phương pháp này có thể mất một thời gian!

Hack 2 - cắt ngắn các bảng theo cách thủ công

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

sẽ cung cấp cho bạn tất cả các tên bảng, với những tên bạn có thể làm như:

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

Khéo léo! Điều này khá hữu ích.
odigity


3

Trong ứng dụng Spring-ified Rails 4, của tôi bin/setupthường được tăng cường để chứa

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

Điều này rất giống với câu trả lời của leviathan , cộng với việc gieo vào DB thử nghiệm, như

rake db:setup # Tạo cơ sở dữ liệu, tải lược đồ và khởi tạo với dữ liệu gốc
(cũng sử dụng
db:reset để thả cơ sở dữ liệu trước)

Như nhận xét đã đề cập, nếu chúng ta muốn bỏ DB trước, hãy rake db:resetthực hiện điều đó.

Tôi cũng thấy rằng điều này cung cấp nhiều phản hồi hơn khi so sánh với rake db:test:prepare.


0

Tôi bắt đầu bằng cách bỏ cơ sở dữ liệu thử nghiệm của mình rake db:drop RAILS_ENV=test

khi cố gắng tạo cơ sở dữ liệu thử nghiệm mới, tôi đã gặp sự cố vì tài khoản người dùng của tôi không giống với tài khoản sở hữu cơ sở dữ liệu, vì vậy thay vào đó tôi đã tạo cơ sở dữ liệu trong PostgreSQL.

psqlvào dấu nhắc lệnh và sau đó chạy phần bên dưới để tạo cơ sở dữ liệu thử nghiệm sử dụng tài khoản không phải của riêng bạn. CREATE DATABASE your_database_name OWNER your_db_owner;

sau đó chạy di chuyển của bạn trong môi trường thử nghiệm. rake db:migrate RAILS_ENV=test

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.