2017-10-10 11 views
0

次のコードがあり、私が合格できないとテストしました。コードは、24時間以上前に完了したすべての予約を自動ロックする必要があります。Rails Rspecテストがアプリケーションで動作するときに失敗します

私がテストに入れて、Booking.auto_lock_guestsの最初の行を実行すると、何も起こりません。私はbooking_7と入力して、Booking.auto_lock_guestsと入力した後、それはtrueにロックされます。これは、予約がBooking.allに表示されないように設定する方法と関係がありますか?それとも私がテストを書いたのですか?

ご協力いただければ幸いです。

def self.auto_lock_guests 
    bookings = Booking.where(guests_completed: true, locked: false) 
    bookings.each do |booking| 
     next unless booking.guests_completed_at <= 1.day.ago 
     booking.locked = true 
     booking.save 
    end 
    end 


    context 'auto_lock_guests' do 
    let(:booking_6) { FactoryGirl.create(:booking, date: Date.today - 5.day, guests_completed: true, guests_completed_at: DateTime.now, locked: false)} 
    let(:booking_7) { FactoryGirl.create(:booking, date: Date.today - 5.day, guests_completed: true, guests_completed_at: DateTime.now - 3.day, locked: false)} 
    before do 
     Booking.auto_lock_guests 
    end 
    it 'should only lock bookings with a guests_completed date older than a day ago' do 
     expect(booking_7.locked).to eq(true) 
     expect(booking_6.locked).to eq(false) 
    end 
    end 

答えて

0

私はBooking.auto_lock_guestsを呼び出した後に行動する前にこれを追加するためになってしまったし、それが働きました。

before do 
    Booking.auto_lock_guests 
    booking_7.reload 
    booking_6.reload 
end 
+0

私は 'Booking.auto_lock_guests'を呼び出すときに両方の予約が作成されていないことを確信しているので、これがどのように機能するのか疑問に思っています。 – Magnuss

1

letです。 beforeブロックが実行されると、ブロックはまだ呼び出されていないので、レコードは存在しません。letブロックはまだ呼び出されていません。

どちらかすぐにブロックを実行するか、右Booking.auto_lock_guests

EDIT前booking_6booking_7を呼び出すためにlet!letを変更:booking.saveが成功した天気を

また、あなたがチェックしないでください。 booking.saveが失敗した場合、あなたは決して知りません。 :)

next unless booking.guests_completed_at <= 1.day.agoはおそらく、クエリのように書き換えることができる。where(Booking.arel_table[:guests_completed_at].gt(1.day.ago))

+0

これは修正されていないようですが、今問題を解決しました。保存の確認についてのヒントをありがとう。私は今それを追加しています。 – Georgeheap

1

最初にレコードを繰り返し処理する必要はありません。実際には、すべてのレコードをメモリに格納するとサーバー(またはdynos)メモリが使い果たされるため、アプリケーションのスケーラビリティに問題が発生します。

データベースからレコードを選択して、単一のクエリでそれらを更新することができます。

class Booking 
    def self.auto_lock_guests! 
    bookings = Booking.where(guests_completed: true, locked: false) 
         .where('guests_completed_at <= ?', 1.day.ago) 
    bookings.update_all(locked: true) 
    end 
end 

一度に多くの個々のUPDATEクエリと更新の多くの行の間の実行時間の差は大規模なことができます。あなたが複数のレコードを作成し、変更の期待を使用することができ、それをテストする

:彼らは、初期状態と結果の両方を確認すると、データベースを変更する方法をテストするとき

# use describe and not context for methods. 
describe ".auto_lock_guests" do 
    # let! is not lazy loading 
    let!(:old_booking) { FactoryGirl.create(:booking, date: 7.days.ago, guests_completed: true, guests_completed_at: 3.days.ago, locked: false)} 
    let!(:new_booking) { FactoryGirl.create(:booking, date: Date.today, guests_completed: true, guests_completed_at: DateTime.now, locked: false)} 

    it 'locks a booking with a guests_completed date older than a day ago' do 
    expect do 
     Bookings.auto_lock_guests! && old_booking.reload 
    end.to change { old_booking.locked }.from(false).to(true) 
    end 

    it 'does not lock a when guests_completed date is less than a day ago' do 
    expect do 
     Bookings.auto_lock_guests! && new_booking.reload 
    end.to_not change { new_booking.locked }.from(false).to(true) 
    end 
end 

changeを使用しては非常に良いアイデアです。

+0

実際にデータベースからレコードを取り出す必要がある場合は、[バッチで](http://api.rubyonrails.org/v5.1/classes/ActiveRecord/Batches.html)を実行してください。 – max

+0

また、 'context'はユーザが' ''でサインインされたときに 'context 'のようなコンテキストのために使われるべきです。 'describe'ブロックは、あなたがテストしているものを記述するために使われます。 – max

+0

私はその部分が働いたときに私がここにリストしなかった予約で何かをやっています。私は間違いなくそれを変更していますが、それは来る予約の数を制限しますが、余分な場所を持っている。しかし、私はupdate_allを行うことができないと思うので、予約の配列を失ってしまい、その予約の中でゲストを見つけることができません。 – Georgeheap

関連する問題