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
This is a dependency, and a non-deterministic dependency at that. You need to divide the responsibility of the code up a little more.In our code we always pull out the current date using DateTime.Now (.NET, in our case). How can you unit test such code?
Before:
- There is some code that uses the current datetime to do X.
- 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.
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
How to Create a Custom Sort Method in Ruby
Truncate String When It Is Too Long
How to Interact with a Caldav Server from Ruby
Gem Install Pg for Ruby on Rails
How to Display Image Pointed by Url in Rails
Prawn Doesn't Seem to Push Layout Down When Using Repeat(:All)
Activemodel::Validations on Anonymous Class
How to Deploy a Test App on Dreamhost Rails 3.0.4
Best Way to Create a Blog with Static Pages in Ruby
Does Rails Support a Neat Way of Listening to a Udp Socket
Paperclip and Amazon S3 How to Do Paths
How to Tell a Ruby Method to Expect a Specific Parameter Type
Need Help on Reading Emails with "Mail" Gem in Ruby
Ruby: Converting a Nested Ruby Hash to an Un-Nested One
Why Slicing The Params Hash Poses a Security Issue on Mass-Assignment