使用Rspec + Factory Girl在新线程/进程测试中数据库为空

Edm*_*Lee 5 ruby multithreading rspec ruby-on-rails factory-bot

关注此博客文章,http://blog.arkency.com/2015/09/testing-race-conditions/

我试图测试并发性.但在我的规格中,当我启动新线程或分叉进程时,我无法找到记录.

describe 'test concurrency' do
  let(:order_1) { create(:order) }
  let(:order_2) { create(:order) }
  let(:order_3) { create(:order) }
  let(:order_4) { create(:order) }
  let(:product) { create(:product) }

  it 'test concurrency' do
    wait_for_all_threads = true
    product.update(quantity_available: 4, quantity_sold: 0, quantity_in_carts: 0)
    orders = [order_1, order_2, order_3, order_4]

    # Objects are persisted in here
    # because order_n.persisted => true
    # product.persisted => true
    # product.reload works without issue (and this is essentially what causes the RecordNotFound error in Order#add_item)

    threads = orders.map do |order|
      Thread.new do

        # Objects cannot be found in the database

        true while wait_for_all_threads

        item = order.add_item(product, 1)
        order_items << item
      end
    end

    wait_for_all_threads = false

    threads.each(&:join)

    # ...
    # here comes all the expects ...
    # not gonna post it because it's not what matters in this question
  end
end
Run Code Online (Sandbox Code Playgroud)

经过研究,我设定了这些:

DatabaseCleaner.strategy = :truncation
config.use_transactional_fixtures = false
Run Code Online (Sandbox Code Playgroud)

但没有运气.

所以问题是,在新线程中,没有任何创建的对象可以在数据库中找到.

我在挖掘的一些线索:

  • 当我通过sql客户端直接连接时,数据库是空的.(当我在测试中添加断点并验证对象时persisted?)
  • factory girl/rspec实际上是否将数据提交到数据库?如果没有,那么新线程将无法读取它,因为它仍然在bin日志或内存中?(这提示给我,因为我记得after_commit不会在rspec中运行)

Dan*_*Dan 2

使用 Rails 5 这对我有用。放置在描述中:

self.use_transactional_tests = false
Run Code Online (Sandbox Code Playgroud)

“use_transactional_fixtures”已被弃用。

我还必须通过以下方式绕过 DatabaseCleaner:

it 'tests concurrency', bypass_cleaner: true do

end
Run Code Online (Sandbox Code Playgroud)

然后在rails_helper中(或者你有DatabaseCleaner设置的地方)

config.around(:each) do |example|
  if example.metadata[:bypass_cleaner]
    example.run
  else
    # database cleaner code
  end
end
Run Code Online (Sandbox Code Playgroud)

我希望这对您或其他人有所帮助:)