2012-01-08 26 views
45

Dường như cách được chấp nhận phổ biến nhất để xử lý Selenium và kiểm tra là tránh sử dụng các đồ thị giao dịch và sau đó sử dụng một cái gì đó giống như database_cleaner giữa các thử nghiệm/kịch bản. Gần đây tôi đã chạy vào article sau đó gợi ý cách làm như sau:Tại sao không sử dụng kết nối ActiveRecord được chia sẻ cho Rspec + Selenium?

spec_helper.rb

class ActiveRecord::Base 
    mattr_accessor :shared_connection 
    @@shared_connection = nil 

    def self.connection 
    @@shared_connection || retrieve_connection 
    end 
end 

# Forces all threads to share the same connection. This works on 
# Capybara because it starts the web server in a thread. 
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection 

Điều này có vẻ tải tốt hơn cho hiệu suất hơn so với giải pháp thay thế. Có ai có bất kỳ lý do tại sao điều này không nên được sử dụng?

Trả lời

16

Giải pháp này được viết bởi Jose Valim - được tôn trọng trong cộng đồng Rails và là thành viên của nhóm lõi Rails. Tôi nghi ngờ anh ta sẽ khuyên bạn nên sử dụng nó nếu có vấn đề với nó. Cá nhân tôi không có bất kỳ vấn đề gì.

Chỉ cần lưu ý rằng nếu bạn sử dụng Spork, điều này cần phải ở trong khối each_run để hoạt động.

FWIW - Tôi đã gặp vấn đề về kiểm tra capybara liên tục với bản vá trên trên Postgres. Giải pháp Mike Perham mà @hsgubert có bên dưới dường như đã giải quyết được những vấn đề đó. Tôi bây giờ sử dụng giải pháp đó.

+13

Đây không thực sự là câu trả lời mà là sự hấp dẫn quyền lực. – Felixyz

33

Thực ra có vấn đề với nó. Ví dụ: nếu bạn sử dụng đá quý mysql2, bạn sẽ bắt đầu thấy một số lỗi như:

Mysql2::Error This connection is still waiting for a result 

Vui lòng sử dụng thay thế này. Nó được viết bởi Mike Perham, tất cả các khoản tín dụng cho anh ta.

class ActiveRecord::Base 
    mattr_accessor :shared_connection 
    @@shared_connection = nil 

    def self.connection 
    @@shared_connection || ConnectionPool::Wrapper.new(:size => 1) { retrieve_connection } 
    end 
end 

ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection 

Bạn cũng cần cài đặt gem connection_pool. Điều này sẽ giúp bạn tránh khỏi nhiều cơn đau đầu.

+1

Tôi vẫn nhận được lỗi tương tự với bản vá này. [Một bài đăng trên blog] (http://www.spacevatican.org/2012/8/18/threading-the-rat/) đề xuất một giải pháp khác nhưng nó cũng không giúp ích gì cho tôi. – Tsutomu

+0

Cuối cùng, nguyên nhân của vấn đề của tôi là Ajax. Nếu chúng ta sử dụng hack này, chúng ta nên đợi cho đến khi cuộc gọi Ajax kết thúc trước khi chúng ta thực hiện một truy vấn tới cơ sở dữ liệu. Xem mục nhập blog tuyệt vời của Mike Gehard [Chờ cuộc gọi jQuery Ajax kết thúc ở Cucumber] (http://pivotallabs.com/users/mgehard/blog/articles/1671-waiting-for-jquery-ajax-calls-to-finish- trong dưa chuột). – Tsutomu

+3

http://www.spacevatican.org/2012/8/18/threading-the-rat/ giải thích lý do tại sao công trình này hoạt động. –

1

Tôi đã gặp sự cố khi sử dụng mã bạn đã đề cập trong tệp spec_helper.rb của mình.

Điều gì sẽ xảy ra khi kiểm tra của bạn phụ thuộc vào việc sử dụng kết nối với nhiều cơ sở dữ liệu? Tôi có hai cơ sở dữ liệu tôi cần kết nối khi chạy thử nghiệm. Tôi đã làm một bài kiểm tra đơn giản để kiểm tra những gì đang xảy ra với các kết nối cơ sở dữ liệu mà tôi thiết lập.

class ActiveRecord::Base 
    mattr_accessor :shared_connection 
    @@shared_connection = nil 

    def self.connection 
    @@shared_connection || retrieve_connection 
    end 
end 

# Forces all threads to share the same connection. This works on 
# Capybara because it starts the web server in a thread. 
puts "First Record cxn: #{FirstDatabase::Record.connection}" 
# => First Record cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xe59b524> 
puts "AR Base cxn: #{ActiveRecord::Base.connection}" 
# => AR Base cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xc52761c> 
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection 

puts "First Record cxn: #{FirstDatabase::Record.connection}" 
# => First Record cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xc52761c> 
puts "AR Base cxn: #{ActiveRecord::Base.connection}" 
# => AR Base cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xc52761c> 

Như bạn thấy, trước khi gọi phương thức kết nối được chia sẻ, tôi có hai kết nối cơ sở dữ liệu khác nhau. Sau khi, cuộc gọi phương thức kết nối được chia sẻ, tôi chỉ có một cuộc gọi.

Vì vậy, bất kỳ thử nghiệm nào yêu cầu truy cập vào kết nối cơ sở dữ liệu thứ hai để truy xuất thông tin sẽ không thành công. :(

tôi sẽ gửi vấn đề này và xem có ai đã đến một giải pháp.

+0

Khi tôi bỏ mã đó vào tập lệnh ruby ​​của tôi, tôi đã nhận được điều này. ruby (43221,0x109043000) malloc: *** lỗi cho đối tượng 0x7f915136e8c0: con trỏ được giải phóng không được phân bổ tôi sẽ xem xét rằng một lỗ hổng. – baash05

1

Tôi chỉ làm một đọc chút về vấn đề này bản thân mình. Tôi đã khám phá ra đoạn bạn chia sẻ ở đây trong bài viết trên blog này :.

http://blog.plataformatec.com.br/2011/12/three-tips-to-improve-the-performance-of-your-test-suite/

Để trả lời câu hỏi của bạn trực tiếp, các database cleaner github page cảnh báo rằng nó có thể "kết quả trong những thất bại không xác định" tôi muốn đi ngay phía trước và sử dụng nó, nhưng nếu bạn bắt đầu chạy vào thất bại lạ, có lẽ đây là nơi tốt để bắt đầu tìm kiếm.

1

Có một điều tốt ở cuối bài đăng này.Nó có thể giải thích tại sao tôi nhận được một lỗi MALLOC khi tôi cố gắng để một kịch bản luồng rất đơn giản.

http://apidock.com/rails/ActiveRecord/Base/connection

leente - March 15, 2011 0 thanks 
Don't cache it! 

Don’t store a connection in a variable, because another thread might try to use it when it’s already checked back in into the connection pool. See: ActiveRecord::ConnectionAdapters::ConnectionPool 

connection = ActiveRecord::Base.connection 

threads = (1..100).map do 
    Thread.new do 
    begin 
     10.times do 
     connection.execute("SELECT SLEEP(1)") # WRONG 
     ActiveRecord::Base.connection.execute("SELECT SLEEP(1)") # CORRECT 
     end 
     puts "success" 
    rescue => e 
     puts e.message 
    end 
    end 
end 

threads.each(&:join) 
2

Các DatabaseCleaner gem readme trả lời "tại sao không" câu hỏi của bạn theo cách này:

Một cách tiếp cận phổ biến là buộc tất cả các quy trình để sử dụng kết nối cơ sở dữ liệu tương tự (common ActiveRecord hack) tuy nhiên cách tiếp cận này đã được báo cáo dẫn đến thất bại không xác định.

Các vấn đề liên quan