Unit Testing Code Which Gets Current Time

Unit testing code which gets current time

Mocking Time.now or Date.today seems straightforward enough, would look something like:

require 'rubygems'
require 'test/unit'
require 'mocha'

class MyClass

def foo
Time.now
end

end

class MyTest < Test::Unit::TestCase

def test_foo
assert true
t = Time.now
Time.expects(:now).returns(t)
assert_equal t, MyClass.new.foo
end

end

How can I test a function that uses DateTime to get the current time?

So the standard approach to solving this relies on accepting that in your current implementation you have a static, implicit, undeclared dependency on an object which provides the current time (wrapped in a the new instance of the DateTime object). If you did this with your own code (rather than a class from the framework/language) you would not be able to test easily either.

The solution is to stop using the implicit undeclared dependency and declare your implicit dependency explictly. I would do this by creating a DateTimeProvider (or DateTimeFactory) interface which has a method GetCurrentDateTime. Pass this into your constructor for your CommandHistoryCreator and pass it into the CommandHistory constructor. The CommandHistory will then ask the provider to get the current date time object rather than creating a new one itself, and can carry on as it is.

This will allow you to provider a mock DateTime in your tests and check that the CommandHistory is persisted with the correct DateTime

Unit testing code that does date processing based on today's date

In our code we always pull out the current date using DateTime.Now (.NET, in our case). How can you unit test such code?

This is a dependency, and a non-deterministic dependency at that. You need to divide the responsibility of the code up a little more.

Before:

  • There is some code that uses the current datetime to do X.

After:

  • There should be some code that is responsible for getting the current datetime.
  • There should be some code that uses a datetime to do X.

These two sets of code should not be dependent on each other.

This pattern of seperating dependencies works for other cases as well (database, filesystem, etc).

Unit Testing: DateTime.Now

The best strategy is to wrap the current time in an abstraction and inject that abstraction into the consumer.


Alternatively, you can also define a time abstraction as an Ambient Context:

public abstract class TimeProvider
{
private static TimeProvider current =
DefaultTimeProvider.Instance;

public static TimeProvider Current
{
get { return TimeProvider.current; }
set
{
if (value == null)
{
throw new ArgumentNullException("value");
}
TimeProvider.current = value;
}
}

public abstract DateTime UtcNow { get; }

public static void ResetToDefault()
{
TimeProvider.current = DefaultTimeProvider.Instance;
}
}

This will enable you to consume it like this:

var now = TimeProvider.Current.UtcNow;

In a unit test, you can replace TimeProvider.Current with a Test Double/Mock object. Example using Moq:

var timeMock = new Mock<TimeProvider>();
timeMock.SetupGet(tp => tp.UtcNow).Returns(new DateTime(2010, 3, 11));
TimeProvider.Current = timeMock.Object;

However, when unit testing with static state, always remember to tear down your fixture by calling TimeProvider.ResetToDefault().

Time dependent unit tests

Joda time supports setting a "fake" current time through the setCurrentMillisFixed and setCurrentMillisOffset methods of the DateTimeUtils class.

See https://www.joda.org/joda-time/apidocs/org/joda/time/DateTimeUtils.html

Java Unit Testing method that uses new Date() for current date

I understand that you cannot change the method that you need to test. Unfortunately this also means that you are stuck with the old and often not very programmer-friendly Date class (I am assuming java.util.Date).

Edit: The no-arg Date constructor that your method uses in turn uses System.currentTimeMillis(), a static native method. I didn’t know there were tools that could mock contructors and static native methods, but was informed by comment and answer by @Rogério, the developer of JMockit, that such mocking tools exist.

In any case, there is an alternative: you calculate some number of days from today, pass the resulting Date to the method and check that you get the number back you used in your calculation. This will work on any day and requires no mocking/stubbing.

In the code below I am assuming that the getDaysUntil method should discard the hours and minutes and just look at the date in the computer’s time zone. If the real requirements differ, you can probably make the appropriate adjustments to my code.

We want to take into account that the method may run over midnight. If so, I consider the result undefined since we do not know whether the Date object was constructed before or after midnight. In this case I simply try again, assuming the test will finish before the next midnight.

@Test
public void testGetDaysUntil() {
A instanceUnderTest = new A();
for (int daysToTest = 0; daysToTest <= 400; daysToTest++) {

LocalDate today;
int result;
do {
today = LocalDate.now(); // do this in each iteration in case day changes underway
LocalDate targetDate = today.plusDays(daysToTest);
Date midnightAtStartOfDay = Date.from(targetDate.atStartOfDay(ZoneId.systemDefault())
.toInstant());
result = instanceUnderTest.getDaysUntil(midnightAtStartOfDay);
} while (! today.equals(LocalDate.now())); // if we have passed midnight, try again
assertEquals(daysToTest, result);

do {
today = LocalDate.now();
LocalDate targetDate = today.plusDays(daysToTest);
Date nearMidnightAtEndOfDay = Date.from(targetDate.atTime(23, 59, 59, 400_000_000)
.atZone(ZoneId.systemDefault())
.toInstant());
result = instanceUnderTest.getDaysUntil(nearMidnightAtEndOfDay);
} while (! today.equals(LocalDate.now()));
assertEquals(daysToTest, result);
}
}

I have used the Java 8 classes for the date and time calculations. If you cannot use Java 8, Calendar and/or GregorianCalendar can be used, they may be just a little more cumbersome for this job, but at least can be converted to Date easily.

Is there an easy way to stub out time.Now() globally during test?

With implementing a custom interface you are already on the right way. I take it you use the following advise from the golang-nuts thread you've posted:



type Clock interface {
Now() time.Time
After(d time.Duration) <-chan time.Time
}

and provide a concrete implementation

type realClock struct{}
func (realClock) Now() time.Time { return time.Now() }
func (realClock) After(d time.Duration) <-chan time.Time { return time.After(d) }

and a testing implementation.


Original

Changing the system time while making tests (or in general) is a bad idea.

You don't know what depends on the system time while executing tests and you don't want to find out the hard way by spending days of debugging into that. Just don't do it.

There is also no way to shadow the time package globally and doing that would not do
anything more you couldn't do with the interface solution. You can write your own time package
which uses the standard library and provides a function to switch to a mock time library for
testing if it is the time object you need to pass around with the interface solution that is bothering you.

The best way to design and test your code would probably be to make as much code stateless as possible.

Split your functionality in testable, stateless parts. Testing these components separately is much easier then. Also, fewer side effects means that it is much easier to make the code run concurrently.

How to write unit test for function returning time after one hour

You could try mocking the time provider and setting up the time.Now() function in your mock to return a preset value which you control. In production you can forward this to a call to the actual time.

How to write an unit test for 'getCurrentTime()' function?

At least you can check if result is not null and if you call it twice, second result is greater than first.

Unit Testing: How to test a method returning current time

This method is very likely just a wrapper around a call to the standard library. The standard library doesn't need any testing. All you need to test is the code which takes something from the standard library and transforms it into the format you need. So I would suggest you to move this code to a separate method and test it by not feeding it the current value returned from the standard library, but fixed values with known correct results.



Related Topics



Leave a reply



Submit