为什么不为Rspec + Selenium使用共享的ActiveRecord连接?

看来,处理Selenium和testing的最普遍接受的方式是避免使用事务性的装置,然后在testing/场景之间使用诸如database_cleaner之类的东西。 我最近碰到下面的文章 ,build议做以下几点:

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 

这似乎比替代品更好的性能。 有没有人有任何理由为什么不应该使用?

这个解决scheme是由Jose Valim撰写的 – 在Rails社区中受到好评,是Rails核心团队的成员。 我怀疑他会推荐使用它,如果有问题的话。 我个人没有任何问题。

请注意,如果您使用Spork,则需要在each_run块中运行。

FWIW – 我在Postgres上面的补丁上有间歇性的水豚testing问题。 @hsgubert下面的Mike Perham解决scheme似乎已经解决了这些问题。 我现在正在使用该解决scheme。

其实有问题。 例如,如果你使用gem mysql2,你会看到一些错误,如:

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

请改用这个。 这是由迈克·佩勒姆写的,所有的信用给他。

 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 

你也需要安装gem connection_pool 。 这将使您免于许多头痛。

DatabaseCleaner gem自述以这种方式回答你“为什么不”的问题:

一个常见的方法是强制所有进程使用相同的数据库连接( 常见的ActiveRecord黑客 ),但是这种方法已经被报告导致非确定性的失败。

我遇到了一个问题,使用您在我的spec_helper.rb文件中提到的代码。

当您的testing依赖于使用多个数据库的连接时会发生什么? 当我运行testing时,我需要连接两个数据库。 我做了一个简单的testing来检查我build立的数据库连接发生了什么。

 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> 

正如你所看到的,在我调用共享连接方法之前,我有两个不同的数据库连接。 之后,共享连接方法调用,我只有一个。

所以任何需要去第二个数据库连接来检索信息的testing都会失败。 🙁

我要发布这个问题,看看有没有人来解决。

我只是自己读一下这个。 我在这篇博文中发现了你在这里分享的片段:

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

要直接回答你的问题, 数据库清理github页面提醒说,它可能导致“非确定性故障”。 我会马上开始使用它,但是如果你开始遇到奇怪的失败,也许这是一个开始寻找的好地方。

这篇文章的结尾有个好东西。 这可能解释为什么当我尝试一个非常简单的线程脚本时,我得到一个MALLOC错误。

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)