我已经实现了 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
中创建的模型的第一个实例 block (模型#2)而不是在 before(:each)
中创建的模型 block (型号#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。
关于mysql - 数据库在测试环境中排序不正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36495792/