Controlling time in a unit test allows you to test code that depends on the passage of time like Timer
or time comparisons. Dart makes it easy as long as you use the Clock package in code that gets dates instead of using DateTime
directly. For any code using Clock
time can be controlled through the FakeAsync package.
Example Time Test
testWidgets('fakeAsync controls clock time', (tester) async {
final initialTime = DateTime(2022, 12, 30, 8, 17, 32);
final duration = const Duration(hours: 10);
fakeAsync((fa) {
final time1 = clock.now();
expect(time1, initialTime);
fa.elapse(duration);
final time2 = clock.now();
final timeDifference = time2.difference(time1);
expect(timeDifference, duration);
}, initialTime: initialTime);
});
Two key things to note in this example test. First that the test is wrapped in the fakeAsync
method. Second that the first time clock
is used is inside the fakeAsync
wrapper. That’s important, if you access the clock
before fakeAsync
then it will use the real clock instead of the mock. For example, in one test of mine some code accessed clock
in the setup
method of the test and so the test failed because I couldn’t control time.
The date and time that will be reported by clock.now()
initially is controlled through the initialTime
argument to the fakeAsync
method. To make time pass within the test use the FakeAsync
parameter to the callback, in this case I called it fa
. In the example above the line:
fa.elapse(duration);
causes time to pass within the body of the test. The next call to clock.now()
will return a DateTime
that is duration
later than the initial time. Also any Timer
or Future.delayed
or other time dependent code will act as though that amount of time had passed.
You should read the documentation of the FakeAsync
package as it has other uses and affects the execution of your code. The flushMicrotasks
method is particularly useful.