Simple Time Control For Dart Unit Tests

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.

Person sitting in front of clock taking control of time
credit: Oladimeji Ajegbile https://www.pexels.com/@diimejii/

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.

Leave a Reply