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
UnitTest a method that is time-dependent
Two main options:
Create a service that isolates time-dependent functionality and inject its interface into classes that need it. Then you can mock this interface to get the behavior you need for testing.
Use a detouring test framework like Moles (there are a few others out there, as well) that can reroute static method calls like
DateTime.Now
.
How to unit test a time dependent method with JUnit
I would build a unix timestamp in my unitTest based on the current time. The granularity of the result of the method is coarse enough that a few millisecond difference between when you create the argument and when this method is executed will not be material. Granted, you will need to steer clear of the boundary conditions, i.e., a unixTime at 60 minutes and 24 hours.
public void testMinutes() {
Instant minutesAgo = Instant.ofEpochMilli(System.currentTimeMillis() - 15 * 60 * 1000);
String result = getAge(minutesAgo.getEpochSecond());
assertSomething...
}
And so on for hours and days tests.
Time dependent unit tests breaking when run in parallel, any workarounds?
Implement and set a CurrentMillisProvider
that stores "now" in a ThreadLocal<Long>
, as suggested in these Parallelism Tips:
P.S. Joda Time has DateTimeUtils which lets you change the current time used by the library. It's a global variable, but if you call
DateTimeUtils.setCurrentMillisProvider
with aThreadLocal
backed implementation, it'll be reasonably isolated when testing legacy code that uses Joda Time.
How to write time dependent tests Python
freezegun
makes mocking datetime very easy.
from freezegun import freeze_time
@freeze_time("2015-02-25")
def test_third_day_from_now():
assert third_day_from_now() == datetime.datetime(2015, 2, 28)
Testing a time-dependent method
In general, I think it's a good idea to make your nontrivial functions and classes as close to mathematical functions (e.g., sin(x)
), as possible. Given the same input, a mathematical function gives the same output each time, irrespective of the current date, random choices, and so forth.
If your function performs nontrivial logic dependent on the current date or time, pass the current date or time externally to it.
If your function performs random choices, pass it a pseudo-random number generator.
So, for example, instead of:
import datetime
def foo():
...
now = datetime.datetime.now()
...
foo()
Use
import datetime
def foo(now):
...
...
foo(datetime.datetime.now())
This makes your nontrivial code consistent across multiple executions.
You can predictably test it.
If it fails in production, it is easier to reconstruct the problem.
Unit testing code dependent on DateTime.Now
Kata
is dependent on an implementation concretion when it should be dependent on an abstraction. That would allow Kata
the flexibility at accept different implementations of the abstraction.
public class Kata {
private readonly IClock clock;
public Kata(IClock clock) {
this.clock = clock;
}
public int GetAgeFromDOB(DateTime birthday) {
var now = clock.Now;
var age = now.Year - birthday.Year;
if (birthday > now.AddYears(-age)) age--;
return age;
}
}
public interface IClock {
DateTime Now { get; }
}
The two implementations of IClock
can be kept simple based on the requirements stated in the question.
The SystemClock class needs to implement a DateTime method that returns DateTime.Now
public class SystemClock : IClock {
public DateTime Now { get { return DateTime.Now; } }
}
The StaticClock method needs to implement a DateTime method that returns a DateTime value that was passed to its constructor.
public class StaticClock : IClock {
public StaticClock(DateTime now) {
this.Now = now;
}
public DateTime Now { get; private set; }
}
Which should allow you to get the desired results.
Related Topics
Java's Collections.Shuffle Is Doing What
Possible to Use Two Java Classes with Same Name and Same Package
Calling Getters on an Object VS. Storing It as a Local Variable (Memory Footprint, Performance)
Jce Cannot Authenticate the Provider Bc in Java Swing Application
Java JSON Serialization - Best Practice
Hibernate: "Field 'Id' Doesn't Have a Default Value"
Why Is System.Out.Println So Slow
Intellij: Never Use Wildcard Imports
How to Set Connection Timeout with Okhttp
How to Get a Client's MAC Address from Httpservlet
Creating an X509 Certificate in Java Without Bouncycastle
How to Create a New Packaging Type for Maven
Find an Array Inside Another Larger Array
How to Escape Reserved Words in Hibernate's Hql
Check If Int Is Between Two Numbers