# Consistent testing with methods that depend on Date.today

**URL:** <https://www.ruby-forum.com/t/consistent-testing-with-methods-that-depend-on-date-today/52761>\
**Category:** Rails\
**Created:** [January 18, 2006, 7:28pm UTC](https://www.ruby-forum.com/t/consistent-testing-with-methods-that-depend-on-date-today/52761 "2006-01-18T19:28:12Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![zdavidlnx](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/z/839c29/32.png) [@zdavidlnx](https://www.ruby-forum.com/u/zdavidlnx)\
**Post date:** [January 18, 2006, 7:28pm UTC](https://www.ruby-forum.com/t/consistent-testing-with-methods-that-depend-on-date-today/52761/1 "2006-01-18T19:28:12Z")

</div>

Hi everyone

I’m building an app in which quite a bit of data is dependant on dates  
(and times), and I have logic that depends on when ‘today’ is. I’m  
trying to get some better functional tests written, and am unsure of  
the best way to approach it.

The problem is that I want the tests to run against the same data  
every time, whether I run it on Tuesday or Thursday or whatever day.  
My fixtures are dynamic in that they add data relative to the  
beginning of ‘this week’ (day of the week is important for this data  
to make sense, so I can’t go relative to Date.today directly). In one  
of my actions, I return data for the ‘next three days’, and as such,  
tests are run against different data depending on what day of the week  
the tests are run on. This is not what I want - tests should get run  
against the _same_ data each time (imho).

I know this problem has to have been solved in the past, but I just  
can’t seem to put my finger on a clean method to run these tests on a  
consistent set of data. Do people mock out the Date.today method to  
return a specific date, or what?

Thanks for any hints,  
Dave

–  
Dave Goodlad  
removed\_email\_address@domain.invalid or removed\_email\_address@domain.invalid  
[http://david.goodlad.ca/](http://david.goodlad.ca/)

---

<div class="post-metadata">

**Author:** ![zdavidlnx](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/z/839c29/32.png) [@zdavidlnx](https://www.ruby-forum.com/u/zdavidlnx)\
**Post date:** [January 18, 2006, 7:31pm UTC](https://www.ruby-forum.com/t/consistent-testing-with-methods-that-depend-on-date-today/52761/2 "2006-01-18T19:31:13Z")

</div>

David G. wrote:

> I know this problem has to have been solved in the past, but I just  
> can’t seem to put my finger on a clean method to run these tests on a  
> consistent set of data. Do people mock out the Date.today method to  
> return a specific date, or what?  
> I can’t say I’ve had exactly this problem, but that’s the first thing  
> I’d try. Either that or extract out whatever date-retrieval  
> functionality you need to a separate model class which uses Date.\* in  
> the actual app, but static data in a mock.

---

<div class="post-metadata">

**Author:** ![zdavidlnx](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/z/839c29/32.png) [@zdavidlnx](https://www.ruby-forum.com/u/zdavidlnx)\
**Post date:** [January 18, 2006, 11:53pm UTC](https://www.ruby-forum.com/t/consistent-testing-with-methods-that-depend-on-date-today/52761/3 "2006-01-18T23:53:15Z")

</div>

Alex Y. wrote:

> David G. wrote:
> 
> > I know this problem has to have been solved in the past, but I just  
> > can’t seem to put my finger on a clean method to run these tests on a  
> > consistent set of data. Do people mock out the Date.today method to  
> > return a specific date, or what?  
> > I can’t say I’ve had exactly this problem, but that’s the first thing  
> > I’d try. Either that or extract out whatever date-retrieval  
> > functionality you need to a separate model class which uses Date.\* in  
> > the actual app, but static data in a mock.

I’m sure you can apply my approach the following approach to fit your  
problem.

I’ve a file mutable\_time.rb which I include when running my tests.

class \<\< Time  
alias\_method :original\_now, :now

def set(time)  
@now = time  
end

def advance\_now\_in\_seconds(seconds)  
@now ||= now  
@now += seconds  
end

def now  
@now || original\_now  
end

def use\_original\_now  
@now = nil  
end  
end

I don’t use dynamic fixtures - I find it easier to keep the fixtures the  
same - and test different scenarios by changing Time.now - that way it’s  
easier to talk about fixtures when discussing acceptance tests etc.

so if i wanted to test what happens if time is same as the time in my  
fixture then I’d call something like

Time.set(fixture(:item).date)

Hope that helps/

---

<div class="post-metadata">

**Author:** ![zdavidlnx](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/z/839c29/32.png) [@zdavidlnx](https://www.ruby-forum.com/u/zdavidlnx)\
**Post date:** [January 19, 2006, 12:23am UTC](https://www.ruby-forum.com/t/consistent-testing-with-methods-that-depend-on-date-today/52761/4 "2006-01-19T00:23:43Z")

</div>

On 1/18/06, Darragh C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> I’m sure you can apply my approach the following approach to fit your  
> problem.
> 
> I’ve a file mutable\_time.rb which I include when running my tests.
> 
> class \<\< Time  
> [snip]
> 
> I don’t use dynamic fixtures - I find it easier to keep the fixtures the  
> same - and test different scenarios by changing Time.now - that way it’s  
> easier to talk about fixtures when discussing acceptance tests etc.
> 
> so if i wanted to test what happens if time is same as the time in my  
> fixture then I’d call something like
> 
> Time.set(fixture(:item).date)

Do you have any problems with any of Rails’ built-in functionality  
getting confused when you redefine Time#now like that? After some  
experimentation, it seems that the Date class relies on Time#now, so I  
could isolate all of my “meddling” to changing one definition and have  
it remain consistent throughout the app. I’m just concerned that I’ll  
break something subtle in the process!

Dave

> Hope that helps/
> 
> –  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).
> 
> * * *
> 
> Rails mailing list  
> removed\_email\_address@domain.invalid  
> [http://lists.rubyonrails.org/mailman/listinfo/rails](http://lists.rubyonrails.org/mailman/listinfo/rails)

–  
Dave Goodlad  
removed\_email\_address@domain.invalid or removed\_email\_address@domain.invalid  
[http://david.goodlad.ca/](http://david.goodlad.ca/)

---

<div class="post-metadata">

**Author:** ![zdavidlnx](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/z/839c29/32.png) [@zdavidlnx](https://www.ruby-forum.com/u/zdavidlnx)\
**Post date:** [January 19, 2006, 12:35am UTC](https://www.ruby-forum.com/t/consistent-testing-with-methods-that-depend-on-date-today/52761/5 "2006-01-19T00:35:58Z")

</div>

David G. wrote:

> Do you have any problems with any of Rails’ built-in functionality  
> getting confused when you redefine Time#now like that?

I typically have a teardown to reset to normal time -

def teardown  
Time.use\_system\_time  
end

only weirdness I’ve seen is the time report when you run a test can  
start saying billions of seconds - but i think that’s only when i forget  
to have a teardown.

---

<div class="post-metadata">

**Author:** ![zdavidlnx](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/z/839c29/32.png) [@zdavidlnx](https://www.ruby-forum.com/u/zdavidlnx)\
**Post date:** [January 19, 2006, 4:22am UTC](https://www.ruby-forum.com/t/consistent-testing-with-methods-that-depend-on-date-today/52761/6 "2006-01-19T04:22:42Z")

</div>

I’ve had good luck isolating the date-sensitive code and making ‘now’  
a parameter. You can also parameter-ize time-outs and such, and set  
them to short time intervals. Of course, these approaches won’t work  
for some scenarios. It’s one of the toughest test nuts to crack.

There was a good discussion of alternatives in one of the XP books, I  
think, but just can’t find it.

Scott

---

<div class="post-metadata">

**Author:** ![zdavidlnx](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/z/839c29/32.png) [@zdavidlnx](https://www.ruby-forum.com/u/zdavidlnx)\
**Post date:** [January 19, 2006, 1:51am UTC](https://www.ruby-forum.com/t/consistent-testing-with-methods-that-depend-on-date-today/52761/7 "2006-01-19T01:51:44Z")

</div>

I had more or less the same problem, and I solved it by overriding  
Time::now

My app takes timezones and daylight savings time into account, so I  
wanted  
to be able to set “today” to days that are or are not in DST.

I’m also using Salted Login Generator, which does it’s own (different)  
override of Time::now, so I wrote some code that incorporates both  
pieces of  
logic.

Following is my time.rb, which I use only for testing. If you don’t  
care  
about the Salted Login Generator stuff, you can ignore  
“@@advance\_by\_days”  
related stuff.

To use it, you can call “Time.set\_now\_gmt(year, month, day, hour,  
minute,  
second)”, and then call “Time.clear\_now\_gmt”. Better, you can pass a  
block  
into set\_now\_gmt, and the change will only affect that block of code.

require ‘time’

class Time  
@@advance\_by\_days = 0  
cattr\_accessor :advance\_by\_days

#MES- This is some super-funky stuff to test times and timezones. To

# properly test timezones, we need to test at times that are affected

by

# daylight savings time (e.g. to see that DST doesn’t screw up our

# local to UTC conversions, etc.) But we can’t count on tests being

run

# on days that are near a DST switchover, so we need to fake out the

test-

# to pretend that we’re running at one of those times. These

functions

# let the caller set what is considered “now” by the Time class, which

cascades

# to other Time functions.

@@now\_arr = nil

def self.set\_now\_gmt(y, m = 1, d = 1, h = 0, mi = 0, s = 0)  
@@now\_arr = [y, m, d, h, mi, s]  
if block\_given?  
begin  
yield  
ensure  
clear\_now\_gmt  
end  
end  
end

def self.clear\_now\_gmt  
@@now\_arr = nil  
end

def self.set\_advance\_by\_days(days)  
@@advance\_by\_days = days  
if block\_given?  
begin  
yield  
ensure  
@@advance\_by\_days = 0  
end  
end  
end

#MES- OK, this is kinda complicated. I wrote code to set what’s  
considered

# ‘now’ (see the comment above.) However, the Salted Login test code

modifies

# ‘now’ in a different manner- they use an offset, whereas my code

sets an

# absolute time. I’ve merged these approaches into the ‘now’ method.

If  
there’s

# an offset, it’s used. If there’s no offset, but there’s an absolute

date, it’s used.

# If neither tweak is set up, the current time is used.

def self.now  
if Time.advance\_by\_days != 0  
return Time.at(new.to\_i + Time.advance\_by\_days \* 60 \* 60 \* 24 + 1)  
elsif !@@now\_arr.nil?  
self.utc @@now\_arr[0], @@now\_arr[1], @@now\_arr[2], @@now\_arr[3],  
@@now\_arr[4], @@now\_arr[5]  
else  
new  
end  
end

end
