[英]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_6
和booking_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.