简体   繁体   English

在应用程序中运行时,Rails Rspec测试失败

[英]Rails Rspec test fails when it works in app

I have the following code and test that I can't seem to make pass. 我有以下代码并测试似乎无法通过。 The code should be auto locking all bookings that have been completed over 24 hours ago. 该代码应自动锁定所有在24小时前完成的预订。

When I put a pry into the test and run the first line of Booking.auto_lock_guests nothing happens. 当我撬入测试并运行Booking.auto_lock_guests的第一行时,什么都没有发生。 When I type booking_7 and after type Booking.auto_lock_guests then it changes locked to true. 当我输入booking_7并在输入Booking.auto_lock_guests之后,它将更改为true。 Is this something to do with the way let is set up that it is not showing up in Booking.all? 这与让设置未在Booking.all中显示的方式有关吗? Or is it the way I have written the test? 还是我编写测试的方式?

Any help would be greatly appreciated. 任何帮助将不胜感激。

  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

let is lazily evaluated. let被懒惰地评估。 When the before block is executed there are no records, because the let blocks haven't yet been called. 执行before块时,没有记录,因为还没有调用let块。

Either change let to let! 要么改变let let! to execute the block immediately or call booking_6 and booking_7 right before Booking.auto_lock_guests 立即执行区块或在Booking.auto_lock_guests之前Booking.auto_lock_guests致电booking_6booking_7

EDIT: 编辑:

Also you don't check wether the booking.save succeeded. 另外,您不检查booking.save是否成功。保存成功。 If booking.save failed - you would never know. 如果booking.save失败-您将永远不会知道。 :) :)

The next unless booking.guests_completed_at <= 1.day.ago could probably be rewritten as a query: where(Booking.arel_table[:guests_completed_at].gt(1.day.ago)) next unless booking.guests_completed_at <= 1.day.ago可以重写为查询: where(Booking.arel_table[:guests_completed_at].gt(1.day.ago))

You don't need to iterate through the records in the first place. 您无需首先遍历记录。 In fact it will cause problems as your app scales since pulling all those records into memory will exhaust the servers (or dynos) memory. 实际上,这将在您的应用扩展时引起问题,因为将所有这些记录拉入内存将耗尽服务器(或dynos)的内存。

You can select the records from the database and update them in a single query: 您可以从数据库中选择记录,并在单个查询中更新它们:

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

The difference in execution time between many individual UPDATE queries and an updating many rows at once can be massive. 许多单独的UPDATE查询与一次更新许多行之间的执行时间差异可能很大。

To test it you can create multiple records and use change expectations: 要测试它,您可以创建多个记录并使用更改期望:

# 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

Using change is a very good idea when testing methods that change the database as they verify both the initial state and the result. 在测试更改数据库的方法时,使用change是一个好主意,因为这些方法可以验证初始状态和结果。

I ended up having to add this into the before action after calling Booking.auto_lock_guests and it worked. 我最终不得不在调用Booking.auto_lock_guests之后将其添加到before操作中,并且可以正常工作。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM