Suppose I have a widget that behaves differently according to the platform:
RaisedButton
.CupertinoButton
.Example:
@override
Widget build(BuildContext context) {
if (Platform.isAndroid)
return buildRaisedButton();
else if (Platform.isIOS)
return buildCupertinoButton();
else
throw UnsupportedError('Only Android and iOS are supported.');
}
In my widget tests, I want to be able to test both situations, but since Platform
's getters are static, I cannot stub them.
Any ideas on how I can achieve this?
Acknowledge target platform with Theme
:
@override
Widget build(BuildContext context) {
final platform = Theme.of(context).platform;
if (platform == TargetPlatform.iOS)
return buildCupertinoButton();
else
...
}
Stub target platform by setting debugDefaultTargetPlatformOverride
:
testWidgets('`CupertinoButton` is shown in iOS.', (tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
// run your tests
debugDefaultTargetPlatformOverride = null;
});
In order to make your code easier to test, the target platform should be acknowledged from the Theme
, not from Platform
:
@override
Widget build(BuildContext context) {
final platform = Theme.of(context).platform;
if (platform == TargetPlatform.android)
return buildRaisedButton();
else if (platform == TargetPlatform.iOS)
return buildCupertinoButton();
else
throw UnsupportedError('Only Android and iOS are supported.');
}
The getter defaultTargetPlatform
should be able to cover the cases in which you don't have access to the BuildContext
.
To stub the target platform, you must set debugDefaultTargetPlatformOverride
. By default, Android is the target platform for widget tests.
Example:
testWidgets('`CupertinoButton` is shown in iOS.', (tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(MyWidget());
expect(find.byType(RaisedButton), findsNothing);
expect(find.byType(CupertinoButton), findsOneWidget);
debugDefaultTargetPlatformOverride = null;
});
Notice the last line: debugDefaultTargetPlatformOverride = null
.
This is necessary because, in the binding process that happens inside the function testWidgets()
, the method BindingBase.initServiceExtensions()
determines — based on the OS — the value of debugDefaultTargetPlatformOverride
. If the operating system is not mobile (Android, iOS or Fuchsia), null
gets attributed.
At the end of the test, testWidgets()
calls the function debugAssertAllFoundationVarsUnset()
that checks whether debugDefaultTargetPlatformOverride
is null
to make sure you didn't forget to reset it to the default value. This must be done because debugDefaultTargetPlatformOverride
is a top-level variable that persists across tests.
Important: You might be tempted to move debugDefaultTargetPlatformOverride = null
to tearDown()
, but it won't work since debugAssertAllFoundationVarsUnset()
is called before tearDown()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With