如何在 Flutter 中存根目标平台

How to stub target platform in Flutter

假设我有一个根据平台表现不同的小部件:

示例:

@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.');
}

在我的 widget tests 中,我希望能够测试这两种情况,但由于 Platform 的 getter 是静态的,我无法对它们进行存根。

关于如何实现此目标的任何想法?

tl;博士

确认目标平台 Theme:

@override
Widget build(BuildContext context) {
  final platform = Theme.of(context).platform;

  if (platform == TargetPlatform.iOS) 
    return buildCupertinoButton();
  else 
    ...
}

存根目标平台通过设置 debugDefaultTargetPlatformOverride:

testWidgets('`CupertinoButton` is shown in iOS.', (tester) async {
  debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
  
  // run your tests

  debugDefaultTargetPlatformOverride = null;
});

正在确认目标平台

为了让您的代码更容易测试,目标平台应该从 Theme 确认,而不是从 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.');
}

getter defaultTargetPlatform 应该能够涵盖您无法访问 BuildContext.

的情况

存根目标平台

要存根目标平台,您必须设置debugDefaultTargetPlatformOverride。默认情况下,Android 是小部件测试的目标平台。

示例:

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;
});

注意最后一行:debugDefaultTargetPlatformOverride = null.

这是必要的,因为在函数 testWidgets() 内部发生的绑定过程中,方法 BindingBase.initServiceExtensions() 根据 OS 确定 [=15= 的值].如果操作系统不是移动操作系统(Android、iOS 或 Fuchsia),null 会被归因。

在测试结束时,testWidgets() 调用函数 debugAssertAllFoundationVarsUnset() 检查 debugDefaultTargetPlatformOverride 是否为 null 以确保您没有忘记重置它到默认值。必须这样做,因为 debugDefaultTargetPlatformOverride 是一个在测试中持续存在的顶级变量。

重要提示:您可能想将 debugDefaultTargetPlatformOverride = null 移动到 tearDown(),但它不会起作用,因为之前调用了 debugAssertAllFoundationVarsUnset() tearDown().