【问题标题】:Activerecord create method sometimes doesn't work in timeActiverecord 创建方法有时不能及时工作
【发布时间】:2016-09-23 02:29:52
【问题描述】:

我在使用以下代码时遇到问题,它只在我运行它的某些时候通过。

require_relative 'spec_helper'
require 'pry'

RSpec.describe Round do
  testFruit = [Fruit.create(name: "Anjou Pear", unit: "10/LB", price: 13.24), Fruit.create(name: "Anjou Bear", unit: "10/LB", price: 15.24)]

  before(:each) do |variable|
    @round = Round.new
  end

  it 'returns all fruit in the current round of ordering' do
    expect(@round.fruits).to  match_array(testFruit)
  end
  it 'lets you clear the list for the next round' do
    @round.next
    expect(@round.fruits).to match_array([])
  end
end

@round.fruits 定义为

def fruits
  Fruits.all
end

所以我理解Fruits.all 必须等待 testFruits 被持久化到数据库中,我猜这没有及时完成?有没有办法可以用 rspec 异步测试这个,我应该以不同的方式设计我的测试以避免这个问题吗?

我得到的错误是 ``` 失败/错误:expect(@round.fruits).to match_array(testFruit)

   expected collection contained:  [#<Fruit id: 53, pic: nil, description: nil, name: "Anjou Pear", unit: "10/LB", price: #<BigDecimal:2...l:206de28,'0.1524E2',18(27)>, created_at: "2016-09-27 18:18:23", updated_at: "2016-09-27 18:18:23">]
   actual collection contained:    []

```

【问题讨论】:

  • 将 testFruit = [...] 移到 before(:each) 中作为 @testFruit = [...] 并且它应该可以工作,您不要在示例之外或之前创建对象( :each) 块或将留在数据库中
  • 所以在 before(:each) 块中创建的对象被删除/不会在运行规范后保留在数据库中?
  • 是的,在 before(:each) 块中创建的对象不会在下一个规范中持续存在。如果你在 before(:each) 之外创建了一些东西(例如 before(:all) ),你必须在你的规范之后删除它(使用 after(:all) 块)或使用数据库清理器 gem(如 DatabaseCleaner )或者你'最终会得到一个充满旧运行垃圾的测试数据库。

标签: ruby activerecord rspec


【解决方案1】:

有没有办法用 rspec 异步测试这个

是的,但我不会在这里讨论,因为如果您以更符合当前最佳实践的方式编写测试,则没有必要。

我应该以不同的方式设计我的测试来避免这个问题吗?

是的,这里的问题很可能是由于测试之间所谓的“泄漏状态”造成的。理想的情况是,每个测试都应该与每个测试完全隔离,这样您就可以按任何顺序运行测试,并且它们会得到相同的结果。

问题在于您刚刚位于范围内的 testFruit 数组。如果此 Array 或其在数据库中创建的对象发生更改,该更改将泄漏到随后的测试中。

我建议改为这样编写测试:

RSpec.describe Round do
  let!(:round) { Round.new }
  let!(:test_fruit) do
    [
      Fruit.create(name: "Anjou Pear", unit: "10/LB", price: 13.24),
      Fruit.create(name: "Anjou Bear", unit: "10/LB", price: 15.24)
    ]
  end

  describe "#fruits" do
    it 'returns all fruit in the current round of ordering' do
      expect(round.fruits).to match_array(testFruit)
    end
  end

  describe "#next" do
    it 'lets clears the list for the next round' do
      round.next

      expect(round.fruits).to match_array([])
    end
  end
end

这利用了 RSpec 的 let! 功能,您可以阅读有关 here 的信息。基本上,它可以确保您在每次测试之间获得一致的设置。

最后,您不必担心有关数据库写入的任何异步问题; Rails 在从数据库收到数据确实已写入的成功回复之前不会继续运行。

【讨论】:

  • 感谢您的回答,但我无法理解泄漏状态有时如何导致我的测试失败。
  • 抱歉,我现在明白了,我的 specs_helper 中有 config.order = :random
  • @RyderBergerud 这正是推荐使用随机测试顺序的原因,因为它以间歇性故障的形式突出了泄漏状态
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-03-24
  • 1970-01-01
  • 1970-01-01
  • 2017-02-20
  • 2018-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多