【问题标题】:How to test Flutter widgets on different screen sizes?如何在不同的屏幕尺寸上测试 Flutter 小部件?
【发布时间】:2019-05-11 09:45:10
【问题描述】:

我有一个 Flutter 小部件,它根据屏幕大小显示额外的数据。有谁知道在多种不同屏幕尺寸上测试这个小部件的方法?

我查看了widget_tester 源代码,但找不到任何东西。

【问题讨论】:

  • 测试是指单元测试/类似测试还是手动测试?
  • 通过测试,我的意思是小部件测试,就像测试特定小部件是否可见,类似于单元测试。 flutter.io/docs/cookbook/testing/widget

标签: flutter flutter-test


【解决方案1】:

您可以使用WidgetTester 指定自定义表面尺寸

以下代码将运行屏幕尺寸为 42x42 的测试

import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  testWidgets("foo", (tester) async {
    tester.binding.window.physicalSizeTestValue = Size(42, 42);

    // resets the screen to its original size after the test end
    addTearDown(tester.binding.window.clearPhysicalSizeTestValue);

    // TODO: do something
  });
}

【讨论】:

  • 如果带有 Scaffold 父级的小部件正在测试中,则需要像这样添加 Material app 作为包装器:await tester.pumpWidget(new MaterialApp(home: new LoginScreen()));
  • 默认尺寸是多少?我做了1200、2400,还是比默认尺寸小。
  • 宽800高600
  • @RémiRousselet 我听从了你的建议,但它不适用于文本
【解决方案2】:

你可以试试这个小部件来测试你的小部件实时改变屏幕大小

屏幕尺寸测试

https://pub.dev/packages/screen_size_test

预览

演示 https://dartpad.dartlang.org/43d9c47a8bf031ce3ef2f6314c9dbd52

代码示例

import 'package:screen_size_test/screen_size_test.dart';
...
MaterialApp(
  title: 'Demo',
  builder: (context, child) => ScreenSizeTest(
    child: child,
  ),
  home: Scaffold(
    body: ListView(
      children: List.generate(
          20,
          (index) => Container(
                padding: EdgeInsets.all(10),
                child: Placeholder(),
              )),
    ),
  ),
)

【讨论】:

  • 滑块不工作
【解决方案3】:

有一个叫device_preview的包可以模拟你在不同设备上运行的flutter应用。

【讨论】:

    【解决方案4】:

    @rémi-rousselet 的解决方案完美运行!

    此外,如果您想测试方向变化,请尝试以下操作:

    const double PORTRAIT_WIDTH = 400.0;
    const double PORTRAIT_HEIGHT = 800.0;
    const double LANDSCAPE_WIDTH = PORTRAIT_HEIGHT;
    const double LANDSCAPE_HEIGHT = PORTRAIT_WIDTH;
    
    final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
    
    await binding.setSurfaceSize(Size(PORTRAIT_WIDTH, PORTRAIT_HEIGHT));
    await tester.pumpWidget(MyWidget());
    
    // test in portrait
    
    await binding.setSurfaceSize(Size(LANDSCAPE_WIDTH, LANDSCAPE_HEIGHT));
    await tester.pumpAndSettle();
    
    // OrientationBuilder gets triggered
    
    // test in landscape
    

    【讨论】:

      【解决方案5】:

      不知道为什么,但@rémi-rousselet 的解决方案对我不起作用。我必须使用 binding.window.physicalSizeTestValuebinding.window.devicePixelRatioTestValue 指定屏幕尺寸,以便输出完全确定

      我为像我这样的 Flutter 初学者添加了更多代码。检查这个:

      void main() {
      
        final TestWidgetsFlutterBinding binding =
          TestWidgetsFlutterBinding.ensureInitialized();
      
        testWidgets("Basic layout test (mobile device)", (tester) async {
          binding.window.physicalSizeTestValue = Size(400, 200);
          binding.window.devicePixelRatioTestValue = 1.0;
      
          await tester.pumpWidget(new MyApp());
      
          expect(find.byType(MyHomePage), findsOneWidget);
          // etc.
        });
      }
      

      【讨论】:

      • 谢谢,这个对我有用(setSurfaceSize 没有)。
      • 这里一样,setSurfaceSize() 对我不起作用,但您的解决方案可以。谢谢。
      • @VizGhar 我听从了您的建议,但我无法正常处理文本,请查看 stackoverflow.com/questions/62447898/…github.com/flutter/flutter/issues/59755
      • 添加 devicePixelRatioTestValue 效果很好!
      • 对于在尝试此操作时遇到类型转换错误的任何人,请添加 as TestWidgetsFlutterBinding 所以整个事情将是 final TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized() as TestWidgetsFlutterBinding;
      【解决方案6】:

      虽然@Rémi Rousselet 的回答很有帮助,但并没有完全解决我的问题。事实证明,我可以将待测小部件包装在 MediaQuery 小部件中并设置大小。

      import 'package:flutter/material.dart';
      import 'package:flutter_test/flutter_test.dart';
      
      void main() {
        Widget makeTestableWidget({Widget child, Size size}) {
          return MaterialApp(
            home: MediaQuery(
              data: MediaQueryData(size: size),
              child: child,
            ),
          );
        }
      
        testWidgets("tablet", (tester) async {
          final testableWidget = makeTestableWidget(
            child: WidgetUnderTest(),
            size: Size(1024, 768),
          );
      
          ...
        });
      
        testWidgets("phone", (tester) async {
          final testableWidget = makeTestableWidget(
            child: WidgetUnderTest(),
            size: Size(375, 812),
          );
      
          ...
        });
      }
      

      【讨论】:

      • 这并不完全正确。它并没有真正改变大小,而是模拟 MediaQuery。 LayoutBuilderRenderObjects 或黄金测试之类的内容仍将基于默认大小。
      • 啊,好吧,当我尝试使用 TestWidgetsFlutterBinding 时,它没有任何影响,因为在我的小部件中,我从 MaterialApp 小部件中创建的 MediaQuery 获取屏幕尺寸。如果我删除 MaterialApp 小部件,它会引发关于 textDirection 为空的错误,所以这似乎是最好的选择,但显然不是每种情况下的最佳选择。
      • 我建议将我的答案标记为解决方案(除非您不同意),因为模拟 MediaQuery 很少需要解决方案。
      猜你喜欢
      • 2019-07-12
      • 2020-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-10
      相关资源
      最近更新 更多