'How to test code that uses DateTime.now in Flutter?
I have this class:
import 'package:flutter/material.dart';
class AgeText extends StatelessWidget {
final String dateOfBirth;
const AgeText({Key key, @required this.dateOfBirth}) : super(key: key);
@override
Widget build(BuildContext context) {
final age = _calculateAge();
return Text(age.toString());
}
int _calculateAge() {
final dateOfBirthDate = DateTime.parse(dateOfBirth);
final difference = DateTime.now().difference(dateOfBirthDate);
final age = difference.inDays / 365;
return age.floor();
}
}
I'd like to test that it produces the correct age when a date of birth is passed into it. What is the best way to do this in Flutter?
SOLUTION: For those interested, here's the solution using @Günter Zöchbauer's suggestion of the clock package.
My widget class:
import 'package:flutter/material.dart';
import 'package:clock/clock.dart';
class AgeText extends StatelessWidget {
final String dateOfBirth;
final Clock clock;
const AgeText({Key key, @required this.dateOfBirth, this.clock = const Clock()}) : super(key: key);
@override
Widget build(BuildContext context) {
final age = _calculateAge();
return Text(age.toString());
}
int _calculateAge() {
final dateOfBirthDate = DateTime.parse(dateOfBirth);
final difference = clock.now().difference(dateOfBirthDate);
final age = difference.inDays / 365;
return age.floor();
}
}
and my test class:
import 'package:clock/clock.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/age.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets("shows age 30 when date of birth is 30 years ago", (WidgetTester tester) async {
final mockClock = Clock.fixed(DateTime(2000, 01, 01));
final testableWidget = MaterialApp(
home: AgeText(
dateOfBirth: "1970-01-01T00:00:00",
clock: mockClock,
),
);
await tester.pumpWidget(testableWidget);
expect(find.text("30"), findsOneWidget);
});
}
Solution 1:[1]
If you use the clock package for code depending on DateTime.now()
you can easily mock it.
I don't think there is a good way without a wrapper around DateTime.now()
licke the clock
package provides.
Solution 2:[2]
As Günter said, the clock package, maintained by the Dart team, provides a very neat way to achieve this.
Normal usage:
import 'package:clock/clock.dart';
void main() {
// prints current date and time
print(clock.now());
}
Overriding the current time:
import 'package:clock/clock.dart';
void main() {
withClock(
Clock.fixed(DateTime(2000)),
() {
// always prints 2000-01-01 00:00:00.
print(clock.now());
},
);
}
I wrote about this in more detail on my blog.
For widget tests, you need to wrap pumpWidget
, pump
and expect
in the withClock
callback.
Solution 3:[3]
As mentioned here: https://stackoverflow.com/a/63073876/2235274 implement extension on DateTime.
extension CustomizableDateTime on DateTime {
static DateTime _customTime;
static DateTime get current {
return _customTime ?? DateTime.now();
}
static set customTime(DateTime customTime) {
_customTime = customTime;
}
}
Then just use CustomizableDateTime.current
in the production code. You can modify the returned value in tests like that: CustomizableDateTime.customTime = DateTime.parse("1969-07-20 20:18:04");
. There is no need to use third party libraries.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Günter Zöchbauer |
Solution 2 | |
Solution 3 |