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

标签 mysql ruby-on-rails ruby rspec factory-bot

我已经实现了 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/

相关文章:

ruby-on-rails - 在 S3 和 cloudfront 上使用 rails carrierwave 私有(private)文件

ruby-on-rails - Rails 可选/:locale route

ruby - `Dir.entries` 中的排序顺序

Ruby RegEx/pattern-match 用于精确的单词/字符串匹配

mysql - 尝试向 MySQL Innodb Cluster 添加节点

mysql - Logstash 无法连接到 MySQL 数据库

mysql - 使用 PDO 将行插入 MYSQL 表不起作用

PHP 变量变量

ruby-on-rails - Rails 设计自定义注册和登录在同一页面问题

ruby - 从 XSD 生成 Ruby 类