Mocha seems a great way to stub Time.now for testing expiration dates, etc.
with rspec. I can get it to stub a single time easily:
Time.stubs(:now).returns(Time.at(1))
but what I'd really like to do is do that multiple times during a test:
specify "with an expired cookie should return nil"
Time.stubs(:now).returns(Time.parse("Jan 1 2001"))
louie.login
cookie = louie.remember_me
Time.stubs(:now).returns(Time.parse("Oct 1 2001"))
louie.login_with_cookie(cookie).should_be_nil
end
However, only the first stubs call has any effect. I've tried stubbing it
to a FakeTime object:
Time.stubs(:now).returns(FakeTime.now)
but it only looks at the value of FakeTime.now when the stub is created.
Is there a way using Mocha/Stubba to stub a routine and have it call
another for the return value? I've tried creating procs/lambdas, but I
must be doing something wrong - I get an infinite recursion.
Jay Levitt
Jay,
I don't know about Mocha, but you have to be a bit careful about replacing Time.now because the test timings depend on it. The way I do it is as follows. First, I've got a little plugin that includes this:
class Time
@@now = nil
def self.now=(time)
@@now = time
end
def self.forced_now #:nodoc:
@@now || unforced_now
end
class << self
alias_method :unforced_now, :now
alias_method :now, :forced_now
end
end
and then in my test helper:
def at_time(time)
time = Time.parse(time + ' UTC') unless time.instance_of?(Time)
Time.now = time
begin
yield
ensure
Time.now = nil
end
end
That lets me do something like this in a test:
def test_whatever
at_time("Jan 1 2001") do
# Tests go in here.
end
end
Hope that helps!
Cheers,
Pete Yandell
···
On 06/09/2006, at 7:25 AM, Jay Levitt wrote:
Mocha seems a great way to stub Time.now for testing expiration dates, etc.
with rspec. I can get it to stub a single time easily:
Time.stubs(:now).returns(Time.at(1))
but what I'd really like to do is do that multiple times during a test:
specify "with an expired cookie should return nil"
Time.stubs(:now).returns(Time.parse("Jan 1 2001"))
louie.login
cookie = louie.remember_me
Time.stubs(:now).returns(Time.parse("Oct 1 2001"))
louie.login_with_cookie(cookie).should_be_nil
end
However, only the first stubs call has any effect. I've tried stubbing it
to a FakeTime object:
Time.stubs(:now).returns(FakeTime.now)
but it only looks at the value of FakeTime.now when the stub is created.
Is there a way using Mocha/Stubba to stub a routine and have it call
another for the return value? I've tried creating procs/lambdas, but I
must be doing something wrong - I get an infinite recursion.
Jay Levitt
Oops...not paying attention to which list I was reading, so my answer was Rails-specific! The code still applies though, and still has the advantage of restoring time to normality once you're done.
Pete Yandell
···
On 06/09/2006, at 9:21 AM, Pete Yandell wrote:
Jay,
I don't know about Mocha, but you have to be a bit careful about replacing Time.now because the test timings depend on it. The way I do it is as follows. First, I've got a little plugin that includes this:
class Time
@@now = nil
def self.now=(time)
@@now = time
end
def self.forced_now #:nodoc:
@@now || unforced_now
end
class << self
alias_method :unforced_now, :now
alias_method :now, :forced_now
end
end
and then in my test helper:
def at_time(time)
time = Time.parse(time + ' UTC') unless time.instance_of?(Time)
Time.now = time
begin
yield
ensure
Time.now = nil
end
end
That lets me do something like this in a test:
def test_whatever
at_time("Jan 1 2001") do
# Tests go in here.
end
end
Hope that helps!
Cheers,
Pete Yandell
On 06/09/2006, at 7:25 AM, Jay Levitt wrote:
Mocha seems a great way to stub Time.now for testing expiration dates, etc.
with rspec. I can get it to stub a single time easily:
Time.stubs(:now).returns(Time.at(1))
but what I'd really like to do is do that multiple times during a test:
specify "with an expired cookie should return nil"
Time.stubs(:now).returns(Time.parse("Jan 1 2001"))
louie.login
cookie = louie.remember_me
Time.stubs(:now).returns(Time.parse("Oct 1 2001"))
louie.login_with_cookie(cookie).should_be_nil
end
However, only the first stubs call has any effect. I've tried stubbing it
to a FakeTime object:
Time.stubs(:now).returns(FakeTime.now)
but it only looks at the value of FakeTime.now when the stub is created.
Is there a way using Mocha/Stubba to stub a routine and have it call
another for the return value? I've tried creating procs/lambdas, but I
must be doing something wrong - I get an infinite recursion.
Jay Levitt
You can use Mocha to do what you want...
def test_me
time_now = Time.parse("Jan 1 2001")
Time.stubs(:now).returns( lambda { time_now } )
assert_equal Time.parse("Jan 1 2001"), Time.now
time_now = Time.parse("Oct 1 2001")
assert_equal Time.parse("Oct 1 2001"), Time.now
end
The test times should be unaffected. The Time class should get put back to
normal in the test teardown.
For any other questions on Mocha, it's probably better to use the mailing
list - http://rubyforge.org/mailman/listinfo/mocha-developer
···
--
James.
On 06/09/06, Pete Yandell <pete@notahat.com> wrote:
Oops...not paying attention to which list I was reading, so my answer
was Rails-specific! The code still applies though, and still has the
advantage of restoring time to normality once you're done.
Pete Yandell
On 06/09/2006, at 9:21 AM, Pete Yandell wrote:
> Jay,
>
> I don't know about Mocha, but you have to be a bit careful about
> replacing Time.now because the test timings depend on it. The way I
> do it is as follows. First, I've got a little plugin that includes
> this:
>
> class Time
> @@now = nil
>
> def self.now=(time)
> @@now = time
> end
>
> def self.forced_now #:nodoc:
> @@now || unforced_now
> end
>
> class << self
> alias_method :unforced_now, :now
> alias_method :now, :forced_now
> end
> end
>
> and then in my test helper:
>
> def at_time(time)
> time = Time.parse(time + ' UTC') unless time.instance_of?(Time)
> Time.now = time
> begin
> yield
> ensure
> Time.now = nil
> end
> end
>
> That lets me do something like this in a test:
>
> def test_whatever
> at_time("Jan 1 2001") do
> # Tests go in here.
> end
> end
>
> Hope that helps!
>
> Cheers,
>
> Pete Yandell
>
> On 06/09/2006, at 7:25 AM, Jay Levitt wrote:
>
>> Mocha seems a great way to stub Time.now for testing expiration
>> dates, etc.
>> with rspec. I can get it to stub a single time easily:
>>
>> Time.stubs(:now).returns(Time.at(1))
>>
>> but what I'd really like to do is do that multiple times during a
>> test:
>>
>> specify "with an expired cookie should return nil"
>> Time.stubs(:now).returns(Time.parse("Jan 1 2001"))
>> louie.login
>> cookie = louie.remember_me
>>
>> Time.stubs(:now).returns(Time.parse("Oct 1 2001"))
>> louie.login_with_cookie(cookie).should_be_nil
>> end
>>
>> However, only the first stubs call has any effect. I've tried
>> stubbing it
>> to a FakeTime object:
>>
>> Time.stubs(:now).returns(FakeTime.now)
>>
>> but it only looks at the value of FakeTime.now when the stub is
>> created.
>> Is there a way using Mocha/Stubba to stub a routine and have it call
>> another for the return value? I've tried creating procs/lambdas,
>> but I
>> must be doing something wrong - I get an infinite recursion.
>>
>> Jay Levitt
>>
>