Reputation: 5172
Using factory bot, creating variables like so :
let!(:deal) { create(:deal) }
The following sample :
expect {
...stuff that effectively associate an attachment to the deal...
}.to change { deal.attachments.length }.from(0).to(1)
does not pass.
The same test, while reloading the deal :
...to change { deal.reload.attachments.length } ...
does pass.
In frequent other occasions, I end up using this reload
method. It feel like this is not the right way to go at all, and that i'm missing the point
What would be the correct way to test changes on records without having to reload them ?
Upvotes: 0
Views: 517
Reputation: 3465
Let's talk about what's happening:
deal.attachments
is queried twice, once before your expect
block is invoked, and then once after, to compare the difference.
Because rails knows that costs to the database are expensive (performance-wise), it caches the values of has_many
relationships to save on performance. So, the first time deal.attachments
is called is the only time a database query is actually made. Add a reload
forces a second database query, giving you the result you expect.
So, this boils down to "How do I make sure the database is queried each time?"
The method you're using is what I'd consider acceptable but there are some other options. The one I'd suggest is using count
instead of length
.
This will perform the count using SQL.
This guarantees that a SQL query will be made before and after your expect
block is invoked.
expect {
...stuff that effectively associate an attachment to the deal...
}.to change { deal.attachments.count }.by(1)
Upvotes: 3