【问题标题】:Database empty in new Thread / Process testing with Rspec + Factory Girl使用 Rspec + Factory Girl 进行新线程/进程测试中的数据库为空
【发布时间】:2017-03-02 00:08:59
【问题描述】:

在这篇博文之后,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

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

DatabaseCleaner.strategy = :truncation
config.use_transactional_fixtures = false

但没有运气。

所以问题是,在新线程中,在数据库中找不到任何创建的对象。

我正在挖掘的一些线索:

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

【问题讨论】:

  • 嗨...这不是您的所有代码...而且绝对不是与此问题相关的所有代码。您能否向我们展示您实际设置数据库中对象的代码?还有 - 显示您如何测试对象是否在数据库中的代码?
  • @TarynEast 当然,请查看我的编辑。

标签: ruby-on-rails ruby multithreading rspec factory-bot


【解决方案1】:

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

self.use_transactional_tests = false

“use_transactional_fixtures”已被弃用。

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

it 'tests concurrency', bypass_cleaner: true do

end

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

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

我希望这可以帮助你或其他人:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-27
    相关资源
    最近更新 更多