views:

74

answers:

2

I have a bit of code that basically displays the last x (variable, but let's say x is 20 here) updates made in a given table. In one of the unit tests for it, I have this snippet:

EditedItem.push_to_queue(hiddennow)
#create some new entries and save them
20.times{ EditedItem.push_to_queue(random_item) }
Queue.get_entries.each{|entry| assert_not_equal too_far_down, entry}

May or may not be pretty, but it gets the intention across. The hiddennow object has been pushed down in the queue too far and should no longer be returned when get_entries is called.

#this works
SearchObject.find(:all, :order => "id desc")

#this does not, unless the 20.times loop has sleep(1) or something
SearchObject.find(:all, :order => "created_at desc")

This is simplified down a bit, but it looks like the 20.times loop adds things fast enough that the order by clause on created_at cannot distinguish. My questions are, am I doing something fundamentally wrong? If not, what is the better approach to writing a test along these lines?

+1  A: 
DigitalRoss
+1  A: 

DigitalRoss is right. created_at has a one second granularity.

One option is to set the created_at when you create the objects:

old = EditItem.new(:created_at => 1.second.ago)
older = EditItem.new(:created_at => 2.seconds.ago)

Another option is to actually use stubbing to mess with the Time class. The following would work with Rspec, but could be easily accomplished with other mocking frameworks like Mocha.

@seconds = Time.now.to_i
Time.stub!(:now).and_return{Time.at(@seconds += 5) }

This will return a time 5 seconds greater than the previous each time you call Time.now.

I'd recommend the first approach if you can make it work, since it's more clear what you're doing and less likely to have unintended consequences.

samg