Perché non utilizzare connessioni ActiveRecord condivise per Rspec + Selenium?

Sembra il modo più comunemente accettato di trattare il selenium ei test è di evitare l’uso di dispositivi transazionali e quindi di usare qualcosa come database_cleaner tra test / scenari. Recentemente mi sono imbattuto nel seguente articolo che suggeriva di fare quanto segue:

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 

Questo sembra molto meglio per le prestazioni rispetto alle alternative. Qualcuno ha qualche ragione per cui questo non dovrebbe essere usato?

Questa soluzione è stata scritta da Jose Valim, molto rispettato nella community di Rails e membro del core team di Rails. Dubito che consiglieresti di usarlo se ci fossero problemi con esso. Personalmente non ho avuto problemi.

Tieni presente che se usi Spork, questo deve essere nel blocco each_run per funzionare.

FWIW – Ho avuto problemi di test capibara intermittenti con la patch sopra su Postgres. La soluzione di Mike Perham che @hsgubert ha sotto sembra aver risolto questi problemi. Ora sto usando quella soluzione.

In realtà ci sono problemi con esso. Se usi la gem mysql2, ad esempio, inizierai a vedere alcuni errori come:

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

Si prega di usare questo invece. È stato scritto da Mike Perham, tutti crediti a lui.

 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 

Dovrai installare gem connection_pool . Questo ti risparmierà da molti mal di testa.

Il readme della gem DatabaseCleaner risponde alla tua domanda “perché no” in questo modo:

Un approccio comune è quello di forzare tutti i processi a utilizzare la stessa connessione al database ( comune attacco ActiveRecord ), tuttavia questo approccio è stato segnalato per provocare errori non deterministici.

Ho riscontrato un problema nell’utilizzo del codice che hai citato nel mio file spec_helper.rb.

Cosa succede quando i test dipendono dall’utilizzo di connessioni a più database? Ho due database a cui devo collegarmi quando eseguo i miei test. Ho fatto un semplice test per verificare cosa stava accadendo alle connessioni del database che ho stabilito.

 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: # puts "AR Base cxn: #{ActiveRecord::Base.connection}" # => AR Base cxn: # ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection puts "First Record cxn: #{FirstDatabase::Record.connection}" # => First Record cxn: # puts "AR Base cxn: #{ActiveRecord::Base.connection}" # => AR Base cxn: # 

Come puoi vedere, prima chiamo il metodo di connessione condivisa, ho due diverse connessioni al database. Dopo, la chiamata al metodo di connessione condivisa, ne ho solo una.

Quindi qualsiasi test che richieda di accedere alla seconda connessione al database per recuperare le informazioni avrà esito negativo. 🙁

Ho intenzione di pubblicare questo problema e vedere se qualcuno è arrivato a una soluzione.

Stavo solo leggendo su questo. Ho scoperto lo snippet che hai condiviso qui in questo post del blog:

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

Per rispondere direttamente alla tua domanda, la pagina github del pulitore del database avverte che può “causare errori non deterministici”. Mi piacerebbe andare avanti e usarlo, ma se inizi a incorrere in strani fallimenti, forse questo è un buon posto per iniziare a cercare.

C’è una bella cosa alla fine di questo post. Può spiegare perché ottengo un errore MALLOC quando tento di eseguire uno script di threading molto semplice.

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)