如何在 Flutter 中存根目标平台

Hug*_*sos 7 dart flutter flutter-test

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

  • 如果平台是 Android,它会显示一个RaisedButton.
  • 如果平台是 iOS,它会显示一个CupertinoButton.

例子:

@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.');
}
Run Code Online (Sandbox Code Playgroud)

在我的小部件测试中,我希望能够测试这两种情况,但是由于Platform的 getter 是静态的,我不能存根它们。

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

Hug*_*sos 16

确认目标平台

为了使您的代码更易于测试,应从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.');
}
Run Code Online (Sandbox Code Playgroud)

getterdefaultTargetPlatform应该能够涵盖您无权访问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;
});
Run Code Online (Sandbox Code Playgroud)

注意最后一行:debugDefaultTargetPlatformOverride = null

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

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

重要提示:你也许会移动debugDefaultTargetPlatformOverride = nulltearDown(),但它不会工作,因为debugAssertAllFoundationVarsUnset()之前调用tearDown()