2016-04-08 3 views
1

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への呼び出しがの最初のインスタンスを得ていることが明らかです(モデル#2)で作成されたモデルで、before(:each)ブロック(モデル#1)で作成されたモデルではありません。私はテストに合格

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

にライン

25.times { create(:model) } 

を変更した場合は

。代わりにsleep(0.1)の場合、テストはまだ失敗します。

これは、私のアプリが1秒以内に2つ以上のモデルインスタンスを作成して、破壊するものを選択するときに最も新しいものを選択するということですか?(最も古いものとは異なり、意図した動作です)これはActiveRecordかMySQLのバグでしょうか?

もしそうでなければ、FactoryGirlやRSpecが生産の代表ではないレコードを作成する方法がありますか?私のテストが現実的なシナリオを表していることを確認するにはどうすればよいですか?

答えて

1

時刻列の精度が1秒の場合、同じ秒で作成された項目を区別することはできません(日付のみでソートする場合)。

これが本番環境で問題になる場合は、created_atとidをソートして確定的な順序を適用することができます。 MySQL 5.6以降では、分数秒を格納するdatetimeカラムを作成することもできます。これで問題は解決されませんが、発生頻度は少なくなります。

テスト中であれば、時間を偽ることもできます。レール4.1(私は思う)の現時点でのサポートにはtravelテストヘルパーがあり、タイムキャップの宝石もあります。

+0

ありがとうございました。私は(非常にばかげたことに)MySQLを格納することを信頼し、ActiveRecordはミリ秒の日付を管理しました。あなたが言うように、それはv 5.6からですが、もちろん私は5.5になっています...これはCentOS 7(?)の安定版のようです。私はあなたのアイデアとcreated_atのソートについて好きです、それは十分です。再度、感謝します – Sam

関連する問題