2012-01-08 3 views
45

Parece que la forma más comúnmente aceptada de tratar con Selenium y las pruebas es evitar el uso de dispositivos transaccionales y luego usar algo como database_cleaner entre pruebas/escenarios. Hace poco me encontré con el siguiente article que sugería la siguiente manera:¿Por qué no utilizar las conexiones compartidas de ActiveRecord para 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 

Esto parece muchísimo mejor para el rendimiento que las alternativas. ¿Alguien tiene alguna razón por la cual esto no debería ser utilizado?

Respuesta

16

Esta solución fue escrita por José Valim, muy respetado en la comunidad de Rails y miembro del equipo central de Rails. Dudo que recomiende usarlo si hay problemas con él. Yo personalmente no he tenido ningún problema.

Solo tenga en cuenta que si utiliza Spork, este debe estar en el bloque each_run para funcionar.

FWIW - He tenido problemas intermitentes de prueba de carpincho con el parche anterior en Postgres. La solución de Mike Perham que @hsgubert tiene a continuación parece haber resuelto esos problemas. Ahora estoy usando esa solución.

+13

Esto no es realmente una respuesta, sino un llamado a la autoridad. – Felixyz

33

En realidad hay problemas con él. Si se utiliza el mysql2 gema, por ejemplo, usted comenzará a ver algunos errores como:

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

Utilice este lugar. Fue escrito por Mike Perham, todos los créditos para él.

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 

Deberás instalar la gema connection_pool también. Esto evitará muchos dolores de cabeza.

+1

Todavía recibo el mismo error con este parche. [Una publicación de blog] (http://www.spacevatican.org/2012/8/18/threading-the-rat/) sugiere otra solución, pero tampoco me ayudó. – Tsutomu

+0

Finalmente, la causa de mi problema es Ajax. Si usamos este truco, debemos esperar hasta que finalice la llamada Ajax antes de realizar una consulta a la base de datos. Vea la entrada al blog de Mike Gehard [Esperando las llamadas de jQuery Ajax para terminar en Cucumber] (http://pivotallabs.com/users/mgehard/blog/articles/1671-waiting-for-jquery-ajax-calls-to-finish- in-pepino). – Tsutomu

+3

http://www.spacevatican.org/2012/8/18/threading-the-rat/ explica por qué esto funciona. –

1

He encontrado un problema al usar el código que mencionaste en mi archivo spec_helper.rb.

¿Qué sucede cuando sus pruebas dependen del uso de conexiones a múltiples bases de datos? Tengo dos bases de datos a las que necesito conectarme cuando ejecuto mis pruebas. Hice una prueba simple para verificar lo que sucedía con las conexiones de la base de datos que establezco.

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> 

Como puede ver, antes de llamar al método de conexión compartida, tengo dos conexiones de bases de datos diferentes. Después, la llamada al método de conexión compartida, solo tengo una.

Por lo tanto, cualquier prueba que requiera acceso a la segunda conexión de la base de datos para recuperar información fallará. :(

Voy a publicar este problema y ver si alguien ha llegado a una solución.

+0

Cuando dejé ese código en mi script de ruby, obtuve esto. ruby (43221,0x109043000) malloc: *** error para el objeto 0x7f915136e8c0: el puntero liberado no estaba asignado. Lo consideraría un error. – baash05

1

Estaba haciendo un poco de lectura sobre esto mismo. Me descubrió el fragmento que ha compartido aquí en esta entrada del blog :.

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

Para responder a su pregunta directamente, los database cleaner github page precauciones que puede "dar lugar a fallos no deterministas" me gustaría ir adelante y usarlo, pero si comienza a correr en fallos extraños, tal vez este es un buen lugar para empezar a buscar.

1

Hay algo bueno al final de esta publicación.Puede explicar por qué obtengo un error MALLOC cuando intento un script de subprocesamiento muy simple.

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

El readme DatabaseCleaner gem responde a su "por qué no" pregunta de esta manera:

Un enfoque común es forzar a todos los procesos a utilizar la misma conexión de base de datos (common ActiveRecord hack) sin embargo Se ha informado que este enfoque da como resultado fallas no deterministas.

Cuestiones relacionadas