数据库在测试环境中排序不正确?

Database sorting incorrectly in test environment?

我已经实施 a solution similar to this 来修剪我的数据库。

# model.rb
after_create do
  self.class.prune(ENV['VARIABLE_NAME'])
end
def self.prune(max)
  order('created_at DESC').last.destroy! until count <= max
end

这在手动测试中效果很好。

在 RSpec 中,测试如下所示:

# spec/models/model_spec.rb
before(:each) do
  @model = Model.new
end

describe "prune" do
  it "should prune the database when it becomes larger than the allowed size" do
    25.times { create(:model) }

    first_model = model.first
    expect{create(:model)}.to change{Model.count}.by(0)
    expect{Model.find(first_model.id)}.to raise_error(ActiveRecord::RecordNotFound)
    end
  end
end

结果是

  1) Model prune should prune the database when it becomes larger than the allowed size
     Failure/Error: expect{Model.find(first_model.id)}.to raise_error(ActiveRecord::RecordNotFound)
       expected ActiveRecord::RecordNotFound but nothing was raised

在测试执行期间检查数据库表明,对 order('created_at DESC').last 的调用正在生成在 25.times 块(模型#2)中创建的模型的第一个实例,而不是在中创建的模型before(:each) 块(模型#1)。

如果我换行

25.times { create(:model) }

25.times { sleep(1); create(:model) }

测试通过。如果我改为 sleep(0.1),测试仍然失败。

这是否意味着如果我的应用程序在 1 秒内创建了两个或多个 Model 实例,它会在选择销毁哪个时选择其中最新的(而不是最旧的,这是预期的行为) ?这可能是 ActiveRecord 或 MySQL 错误吗?

或者如果不是,FactoryGirl 或 RSpec 创建记录的方式是否不代表生产?我如何确定我的测试代表了真实的场景?

如果时间列的精度仅为一秒,则无法区分同一秒内创建的项目(仅按日期排序时)。

如果这是生产中的一个问题,那么您可以对 created_at 和 id 进行排序以强制执行确定性顺序。从 MySQL 5.6 开始,您还可以创建存储小数秒的日期时间列。这并不能消除问题,但会减少发生的频率。

如果它只是在测试中,那么你也可以假装时间。从 rails 4.1(我认为)开始,主动支持有 travel 测试助手,还有 timecop gem。