[nunit-discuss] Setting Date Time for a test

385 views
Skip to first unread message

Kelly Anderson

unread,
Apr 30, 2010, 2:04:38 PM4/30/10
to nunit-...@googlegroups.com
I want to write a test that verifies that something happens if the
code is run after a particular date. I know about SetCulture, is there
a similar attribute to set the system date/time for purposes of
running a test? Should there be?

-Kelly

--
You received this message because you are subscribed to the Google Groups "NUnit-Discuss" group.
To post to this group, send email to nunit-...@googlegroups.com.
To unsubscribe from this group, send email to nunit-discus...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nunit-discuss?hl=en.

David Schmitt

unread,
Apr 30, 2010, 2:15:22 PM4/30/10
to nunit-...@googlegroups.com
On 4/30/2010 8:04 PM, Kelly Anderson wrote:
> I want to write a test that verifies that something happens if the
> code is run after a particular date. I know about SetCulture, is there
> a similar attribute to set the system date/time for purposes of
> running a test? Should there be?

Interesting question, especially since setting the system clock may
affect many other parts of the system, starting at nunit's reporting and
going to other processes on the same machine and beyond.

If you already have some DI container, you can add a CalendarService and
use that to query the current time and to inject a fake system time for
tests. In these cases I envy script hackers who can just say

Date.Expects(:now).returns(some date)

in their test setup and be done with it.



Best Regards, David
--
dasz.at OG Tel: +43 (0)664 2602670 Web: http://dasz.at
Klosterneuburg UID: ATU64260999

FB-Nr.: FN 309285 g FB-Gericht: LG Korneuburg

Kelly Anderson

unread,
Apr 30, 2010, 2:26:55 PM4/30/10
to nunit-...@googlegroups.com
Of course, dependency injection, why didn't I think of that? :-) Very
simple, elegant, and would work great. Guess I haven't done enough TDD
lately. :-/

Still, I wonder if there would be any advantage to an attribute... and
how many other things would it really mess up? If it were an
attribute, NUnit could ignore the system time for other purposes while
it was temporarily reset for a set of tests and it could be more
assured of resetting the clock to the right time when done. If you
reset the system time yourself, you wouldn't get the advantages
possible (in terms of not confusing NUnit) if NUnit did it for you.
Could make the timeout attribute interesting as well... It could be
too much bother to be worth the considerable effort though.

-Kelly

Simone Busoli

unread,
Apr 30, 2010, 3:06:25 PM4/30/10
to nunit-...@googlegroups.com
For this kind of stuff I use an implementation of the Virtual Clock pattern (thanks to my friend Paolo Perrotta for that) which substitutes the use of DateTime with a custom adapter over it. You need to enforce its use in place of the static DateTime accessors throughout the codebase, but it's simply done with static code analysis.

Instead of DateTime, use SystemTime, which has the same static accessors of DateTime with additional behavior, that is:

SystemTime.Now returns the same as DateTime.Now, but SystemTime has

IDisposable SystemTime.FreezeAt(DateTime timeAtWhichToFreeze) { ... }

which can be used during tests and when called makes SystemTime.Now always return timeAtWhichToFreeze until you call Dispose on it.

Charlie Poole

unread,
Apr 30, 2010, 4:22:48 PM4/30/10
to nunit-...@googlegroups.com
Yes, you have to have something like this which is used in both your application
and your tests. Just adding something to NUnit won't impact the SUT unless
you _really_ change the system clock, which isn't advised.

In a pinch - legacy app for example - you can use virtualization and "really"
change the virtual clock.

Charlie

Simone Busoli

unread,
Apr 30, 2010, 6:03:25 PM4/30/10
to nunit-...@googlegroups.com
Even if you're in a legacy app, you can switch from DateTime.Now (or whatever) to SystemTime.Now just the pieces of code you want to test. Painless.

On Fri, Apr 30, 2010 at 22:22, Charlie Poole <nuni...@gmail.com> wrote:
In a pinch - legacy app for example - you can use virtualization and "really"
change the virtual clock.

Charlie Poole

unread,
Apr 30, 2010, 8:02:40 PM4/30/10
to nunit-...@googlegroups.com
Right. I meant to write "third-party app".

Lior Friedman

unread,
May 3, 2010, 11:58:32 AM5/3/10
to nunit-...@googlegroups.com
David wrote:
> In these cases I envy script hackers who can just say
>
>  Date.Expects(:now).returns(some date)
>
> in their test setup and be done with it.

Some mocking tools will allow you to do just that.
specifically:
Microsoft Moles claims to be able to do that
the new JustMock also claims to that (and im preatty certain it can)
and Typemock's Isolator can fake dateTime.Now

Lior

Simone Busoli

unread,
May 3, 2010, 3:51:35 PM5/3/10
to nunit-...@googlegroups.com
I never heard of Moles nor JustMock, nice to see so many tools popping up, although I'm not a fan of such mock-everything tools.

Lior Friedman

unread,
May 4, 2010, 1:47:31 AM5/4/10
to nunit-...@googlegroups.com

Hi Simone

> I never heard of Moles nor JustMock, nice to see so many tools popping up, although I'm not a fan of such mock-everything tools.

Moles is part of the Pex package developed by Microsoft

JustMock is actually very new, its developed by Telerik and its beta was announced just a couple of weeks ago middle of April.

from what I saw it still has some way to go, but it looks like it is going in a good direction.

 

Lior

 

Kelly Anderson

unread,
Jun 23, 2010, 2:32:08 AM6/23/10
to nunit-...@googlegroups.com
On Fri, Apr 30, 2010 at 1:06 PM, Simone Busoli <simone...@gmail.com> wrote:
> For this kind of stuff I use an implementation of the Virtual Clock pattern
> (thanks to my friend Paolo Perrotta for that) which substitutes the use of
> DateTime with a custom adapter over it. You need to enforce its use in place
> of the static DateTime accessors throughout the codebase, but it's simply
> done with static code analysis.
> Instead of DateTime, use SystemTime, which has the same static accessors of
> DateTime with additional behavior, that is:
> SystemTime.Now returns the same as DateTime.Now, but SystemTime has
> IDisposable SystemTime.FreezeAt(DateTime timeAtWhichToFreeze) { ... }
> which can be used during tests and when called makes SystemTime.Now always
> return timeAtWhichToFreeze until you call Dispose on it.

Sadly Simone, the link to the PDF file on the virtual clock page is
broken... don't know if anyone might have that PDF file stashed away.

I think I've done something that might be fairly similar, but I want
to see what others have done before tainting the discussion with what
I've come up with. The stuff I've been working on lately is hard for a
few reasons.

1) I discovered today that the DateTime class is not very good at
dealing with UTC.
2) multiple threading makes all of this more difficult.
3) Wanting tests to be consistent from one run to the next is
impossible in a randomnized time environment simulating randomness in
things like how long it takes an HTTP page to download.

I've had to resort to logging and pouring over pages of logs to figure
out what's going on. Pulling hair.

-Kelly

Gerard Meszaros

unread,
Jun 23, 2010, 2:50:15 AM6/23/10
to nunit-...@googlegroups.com
Keep in mind that not all users can change the real system time. Using
this approach opens you up to test smells like Resource Optmism (it
worked fine on my machine!)

> --
> You received this message because you are subscribed to the Google Groups
> "NUnit-Discuss" group.
> To post to this group, send email to nunit-...@googlegroups.com.
> To unsubscribe from this group, send email to
> nunit-discus...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/nunit-discuss?hl=en.
>
>

--
Sent from my mobile device

Al Gonzalez

unread,
Jun 23, 2010, 12:55:53 PM6/23/10
to nunit-...@googlegroups.com
I wrote "IClock: A Test-Friendly Alternative to DateTime" a method I
been using. The post can be found here:
http://algonzalez.tumblr.com/post/679028234/iclock-a-test-friendly-alternative-to-datetime

Lior Friedman

unread,
Jun 23, 2010, 1:31:10 PM6/23/10
to nunit-...@googlegroups.com
Hi,

What you need is a mocking framework that can handle DateTime.
Typemock Isolator - can handle mocking of DateTime.Now but that’s about it
for now.
JustMock - claims to be able to mock all types from mscorlib, including
DateTime.
And there's also a chance that MS-Moles might be able to do that.

Lior Friedman
Blog  - http://imistaken.blogspot.com

Kelly Anderson

unread,
Jun 23, 2010, 2:02:29 PM6/23/10
to nunit-...@googlegroups.com
On Wed, Jun 23, 2010 at 10:55 AM, Al Gonzalez <a...@nomscon.com> wrote:
> I wrote "IClock: A Test-Friendly Alternative to DateTime" a method I been
> using. The post can be found here:
> http://algonzalez.tumblr.com/post/679028234/iclock-a-test-friendly-alternative-to-datetime

Thanks Al, this is nearly identical to what I had come up with, adding
the Jump Forward feature mentioned in one of the comments. I was
curious if anyone else had come up with a similar idea, and there it
is. Kind of validating to see a similar solution.

I really liked the idea of searching the metadata for uses of
DateTime.Now... you wouldn't happen to have source for that test would
you?

One thing that I added which was really important to the code I am
building was an alternative implementation of Thread.Sleep. I'll
explain it here in case anyone needs a similar function in the future.

If you call Thread.Sleep(1000), then jump your virtual clock forward 5
minutes, the thread would actually sleep for 5 minutes and one second
in the time line of the test. This can cause bad things to happen, so
I implemented a sleep function inside the virtual time class like
this:

public void Sleep(int milliseconds)
{
DateTime sleepUntil = _baseTime + new TimeSpan(0, 0, 0, 0,
milliseconds);
// if Now jumps ahead, then the sleep ends immediately.
while(sleepUntil < Now)
{
Thread.Sleep(10);
}
}

public DateTime Now
{
get
{
TimeSpan span = DateTime.UtcNow - _start;
return _baseTime + span;
}
}

This isn't a perfect solution as the Sleep doesn't REALLY end prior to
the five minutes, but it worked well enough for me at this time. I
suppose the jump forward could take into account that there are
pending sleeps, and "wake up" for a time to get those sleeps to end at
the proper time, but that's YAGNI for me at this point. It took me
quite a while to deduce the interaction between Jump Forward and Sleep
in my multithreaded mess. :-) So hopefully, this will be helpful to
someone in a similar situation in the future.

I am doing all my times in UTC time, which simplifies things, but I
strongly recommend that you do characterization tests on how DateTime
deals with UTC until you have a very firm grasp of how it's dealt with
because it is highly unintuitive (at least to me).

For me, these included the following:

[Test]
public void WhyTheCrapDoesThisPass()
{
var time1 = new DateTime(2010, 01, 01, 8, 0, 0, DateTimeKind.Local);
var time2 = new DateTime(2010, 01, 01, 8, 0, 0, DateTimeKind.Utc);
// REALLY!!!!
Assert.That(time1 == time2, string.Format("time1:{0}
time2:{1}", time1, time2));
}

private const string aDate = "Mon, 14 Jun 2010 16:08:02 GMT";

[Test]
public void ThisIsHowItIsDone()
{
DateTime time = Convert.ToDateTime(aDate);
time = time.ToUniversalTime();
string str = String.Format("{0:r}", time); // "Sun, 09
Mar 2008 16:05:07 GMT" RFC1123
Assert.That(str, Is.EqualTo(aDate));
}


-Kelly

Simone Busoli

unread,
Jun 23, 2010, 4:04:38 PM6/23/10
to nunit-...@googlegroups.com
Well, if you need to check for calls to DateTime.Now you dont't really need to analyze the code. Being a static property you cannot really alias it (unless you're doing something weird with using statements) so a simple full-text search in the code will do.

Simone Busoli

unread,
Jun 23, 2010, 3:59:42 PM6/23/10
to nunit-...@googlegroups.com
Hi Gerard, if you were replying to me I think I can't follow you, can you please expand?
I have your book at hand or I wouldn't be able to know what you mean by Resource Optimism.
My suggestion was not to change the system time, but to use an adapter over DateTime which you can control in your code. If you cannot replace the use of DateTime with something else then you cannot modify the code, and I would say the only way to test that code is to mock DateTime, which is not something I like doing.
As for the use of IClock, I don't like introducing such a dependency just for the sake of testing.

Gerard Meszaros

unread,
Jun 24, 2010, 3:01:14 AM6/24/10
to nunit-...@googlegroups.com
I was commenting on changing the actual system time. The tests won't
run on a server build if the build user isn't allowed to change the
time.

>> > nunit-discus...@googlegroups.com<nunit-discuss%2Bunsu...@googlegroups.com>


>> .
>> > For more options, visit this group at
>> > http://groups.google.com/group/nunit-discuss?hl=en.
>> >
>> >
>>
>> --
>> Sent from my mobile device
>>
>> --
>> You received this message because you are subscribed to the Google Groups
>> "NUnit-Discuss" group.
>> To post to this group, send email to nunit-...@googlegroups.com.
>> To unsubscribe from this group, send email to

>> nunit-discus...@googlegroups.com<nunit-discuss%2Bunsu...@googlegroups.com>

Kelly Anderson

unread,
Jun 28, 2010, 4:57:51 PM6/28/10
to nunit-...@googlegroups.com
Thought I would add one more thing to this thread for completeness...

> For me, these included the following:
>
> [Test]
>        public void WhyTheCrapDoesThisPass()
>        {
>            var time1 = new DateTime(2010, 01, 01, 8, 0, 0, DateTimeKind.Local);
>            var time2 = new DateTime(2010, 01, 01, 8, 0, 0, DateTimeKind.Utc);
>            // REALLY!!!!
>            Assert.That(time1 == time2, string.Format("time1:{0}
> time2:{1}", time1, time2));
>        }

In .Net 3.5 they have added a new class called DateTimeOffset
http://www.danrigsby.com/blog/index.php/2008/08/23/datetime-vs-datetimeoffset-in-net/

Using DateTimeOffset, things make a little more sense (to me anyway).

[Test]
public void SLCandSFO()
{
// one hour later in Salt Lake than in San Francisco
var sfo = new DateTimeOffset(2010, 01, 01, 9, 0, 0, new
TimeSpan(-8, 0, 0));
Console.WriteLine(sfo);
var slc = new DateTimeOffset(2010, 01, 01, 10, 0, 0, new
TimeSpan(-7, 0, 0));
Console.WriteLine(slc);
//Assert.That(sfo.CompareTo(slc), Is.EqualTo(0));
Assert.That(sfo - slc, Is.EqualTo(new TimeSpan(0, 0, 0)));
Assert.That(sfo,Is.EqualTo(slc), string.Format("time1:{0}
time2:{1}", sfo,slc));
}

So anyone stumbling into this in the future will have one more piece
of the puzzle...

-Kelly

Simone Busoli

unread,
Jun 29, 2010, 3:38:51 PM6/29/10
to nunit-...@googlegroups.com
Or something more puzzling to deal with :)
Reply all
Reply to author
Forward
0 new messages