Flutter Widget测试无法正确模拟其他屏幕尺寸 [英] Flutter Widget test cannot emulate different screen size properly

查看:89
本文介绍了Flutter Widget测试无法正确模拟其他屏幕尺寸的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在部署Flutter应用之前,我想在多种屏幕尺寸上对其进行测试,以检查较小屏幕上是否存在 Renderflex溢出


但是,当我第一次在小部件测试期间修改屏幕尺寸以匹配开发过程中使用的设备时,我意识到小部件测试抛出渲染溢出错误即使它在实际设备上没有此类错误,也已经存在。所以我问了这个问题


在Widget测试期间较大的文本大小导致我的应用程序中出现 RenderFlex错误


要重现的步骤:



  1. 现在连接真实设备并使用 fl运行此代码完全运行

lib / main.dart

  import'package:flutter / material.dart'; 

void main(){
runApp(
MaterialApp(
home:TextScaleComparaison(),
),
);
}

类TextScaleComparaison扩展了StatelessWidget {
@override
Widget build(BuildContext context){
final Widget = Scaffold(
body: LayoutBuilder(
builder:(BuildContext context,BoxConstraints约束){
最终宽度= MediaQuery.of(context).size.width;
最终高度= MediaQuery.of(context).size。高度;
final dpr = MediaQuery.of(context).devicePixelRatio;
final textScale = MediaQuery.of(context).textScaleFactor;
final vi = MediaQuery.of(context).viewInsets;
最终VIP = MediaQuery.of(context).viewPadding;
最终字体= DefaultTextStyle.of(context).style.fontFamily;
print( width is $ width and height is $高度和dpi是$ dpr txtScale是$ textScale vi是$ vi vip是$ vip字体是$ font);
return Center(child:Text(这不能那么久!));
},
),
);
返回小部件;
}
}



  1. 检查日志并且您应该看到设备屏幕信息:

对我来说,我得到了:


I / flutter(27450):宽为411.42857142857144,高为797.7142857142857,dpi为2.625 txtScale是1.1 vi是EdgeInsets.zero vip是EdgeInsets(0.0,24.0,0.0,0.0)字体是Roboto


将屏幕宽度高度复制到 textScale devicePixelRatio 转到下面的代码中的下一步。


  1. 编辑下面的代码以添加上述设置,因为我们要在测试中模拟此确切的屏幕尺寸。

test /test.dart

  import'package:flutter / material.dart'; 
import‘package:flutter_test / flutter_test.dart’;
导入 package:my_app / main.dart;
void main(){

testWidgets(
模拟实际屏幕尺寸,
(WidgetTester测试器)异步{
//将其调整为匹配您的实际设备屏幕规格
的最终宽度= 414;
的最终高度= 846;
tester.binding.window.devicePixelRatioTestValue =(2.625);
tester.binding.window。 textScaleFactorTestValue =(1.1);
最终dpi = tester.binding.window.devicePixelRatio;
tester.binding.window.physicalSizeTestValue = Size(width * dpi,height * dpi);
等待测试人员.pumpWidget(
MediaQuery(
data:MediaQueryData(),
子对象:MaterialApp(
home:TextScaleComparaison(),
),
),
);
等待ExpectLater(
find.byType(TextScaleComparaison),
matchesGoldenFile( text.png),
);
},
);
}

使用<$运行 test.dart c $ c> flutter test --update-goldens test / test.dart


这将在 test / text创建一个png文件.png


检查日志:对我来说,它打印出来:


宽度为414.0,高度是846.0和dpi是2.625 txtScale是1.1 vi是EdgeInsets.zero vip是EdgeInsets.zero字体是Roboto


我缺少什么?为什么文本不能显示与真实设备完全相同的文本?


解决方案

这是因为 flutter测试 flutter运行



Flutter的默认字体是 Roboto for Android,如果您未更改其他字体。


  1. 默认Android: Roboto 字体和iOS操作系统:旧金山字体

  2. 自定义



    Ahem 字体方块比您使用的普通字体大得多。因此,它会导致 RenderFlex溢出错误



    解决方案



    要在 flutter测试中实现对设备的近乎完美的仿真,必须下载字体数据,然后加载所使用的确切字体。



    要在小部件测试中加载字体,应在 testWidgets 函数或 setUp

     最终flamante = rootBundle.load('assets / fonts / Flamante-Roma-Medium.ttf'); 
    等待FontLoader(’FlamanteRoma’)
    ..addFont(flamante)
    ..load();

    然后将该字体添加到 ThemeData 之前

     主题:ThemeData(
    fontFamily:'FlamanteRoma',
    ),

    最终测试.dart代码为:

      import'package:flutter / material.dart'; 
    导入的 package:flutter / services.dart;
    import‘package:flutter_test / flutter_test.dart’;
    import‘package:example / test / compare_test_size.dart’;

    void main(){
    testWidgets(
    模拟实际屏幕大小,
    (WidgetTester测试仪)异步{
    final flamante = rootBundle.load ('assets / fonts / Flamante-Roma-Medium.ttf');
    等待FontLoader('FlamanteRoma')
    ..addFont(flamante)
    ..load();

    //调整这些值以匹配您实际的设备屏幕规格
    最终宽度= 411.4;
    最终高度= 797.7;
    tester.binding.window.devicePixelRatioTestValue =(2.625);
    tester.binding.window.textScaleFactorTestValue =(1.1);
    最终dpi = tester.binding.window.devicePixelRatio;
    tester.binding.window.physicalSizeTestValue = Size(width * dpi,height * dpi);
    等待tester.pumpWidget(
    MediaQuery(
    data:MediaQueryData(),
    child:MaterialApp(
    home:TextScaleComparaison(),
    主题:ThemeData(
    fontFamily: FlamanteRoma,
    ),
    ),
    ),
    );
    等待ExpectLater(
    find.byType(TextScaleComparaison),
    matchesGoldenFile( text.png),
    );
    },
    );
    }

    现在重新生成黄金测试并检查png。您将看到真实的文本,而不再是框:



    test / test.png





    并且不要忘记在main.dart中添加相同的字体

      runApp(
    MaterialApp(
    主页:TextScaleComparaison(),
    主题:ThemeData(
    fontFamily:'FlamanteRoma',
    ),
    ),
    );

    也不要忘记更新 pubspec.yaml 并运行 flutter pub get

     -家庭:FlamanteRoma 
    字体:
    -资产:assets / fonts / Flamante-Roma-Medium.ttf


    Before deploying my Flutter app, I wanted to test it on multiple screen sizes to check if there is any Renderflex overflow for smaller screens.

    But I when first modified the screen size during widget testing to match the device I was using during the development, I realized that the widget test is throwing Render overflow errors already, even though it did not have such errors on the real device. So I asked this questions How to fix A RenderFlex overflowed during Widget Test

    But I after further investigation and using Flutter golden feature test which snaps png out of widget tests, I narrowed down the problem to a discrepancy in text size.

    You can see clearly in the reproducible step below that the text during the widget text is WAY BIGGER (on the right) than the actual text in the real device (on the left).

    The bigger text size during Widget test causes the RenderFlex error in my app.

    Steps to reproduce:

    1. Now connect a real device and run this code with flutter run

    lib/main.dart

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(
        MaterialApp(
          home: TextScaleComparaison(),
        ),
      );
    }
    
    class TextScaleComparaison extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final widget = Scaffold(
          body: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
              final width = MediaQuery.of(context).size.width;
              final height = MediaQuery.of(context).size.height;
              final dpr = MediaQuery.of(context).devicePixelRatio;
              final textScale = MediaQuery.of(context).textScaleFactor;
              final vi = MediaQuery.of(context).viewInsets;
              final vip = MediaQuery.of(context).viewPadding;
              final font = DefaultTextStyle.of(context).style.fontFamily;
              print("width is $width and height is $height and dpi is $dpr txtScale is $textScale vi is $vi vip is $vip font is $font");
              return Center(child: Text("This cannot be that long!!"));
            },
          ),
        );
        return widget;
      }
    }
    

    1. Check the logs and you should see device screen info:

    For me I got :

    I/flutter (27450): width is 411.42857142857144 and height is 797.7142857142857 and dpi is 2.625 txtScale is 1.1 vi is EdgeInsets.zero vip is EdgeInsets(0.0, 24.0, 0.0, 0.0) font is Roboto

    Copy the screen width and height to and textScale and devicePixelRatio to the next step in the code below.

    1. Edit the code below to add the above setting because we want to simulate this exact screensize in the test.

    test/test.dart

    import 'package:flutter/material.dart';
    import 'package:flutter_test/flutter_test.dart';
    import 'package:my_app/main.dart';
    void main() {
    
      testWidgets(
        "Emulate real screen size",
        (WidgetTester tester) async {
          // Adjust these to match your actual device screen specs
          final width = 414;
          final height = 846;
          tester.binding.window.devicePixelRatioTestValue = (2.625);
          tester.binding.window.textScaleFactorTestValue = (1.1);
          final dpi = tester.binding.window.devicePixelRatio;
          tester.binding.window.physicalSizeTestValue = Size(width * dpi, height * dpi);
          await tester.pumpWidget(
            MediaQuery(
              data: MediaQueryData(),
              child: MaterialApp(
                home: TextScaleComparaison(),
              ),
            ),
          );
          await expectLater(
            find.byType(TextScaleComparaison),
            matchesGoldenFile("text.png"),
          );
        },
      );
    }
    

    Run test.dart with flutter test --update-goldens test/test.dart

    This will create a png file at test/text.png

    Check the logs: For me it printed:

    width is 414.0 and height is 846.0 and dpi is 2.625 txtScale is 1.1 vi is EdgeInsets.zero vip is EdgeInsets.zero font is Roboto

    What I am missing ? Why can't the text show exactly the same as the real device?

    解决方案

    That is because of the font difference used by flutter test and flutter run.

    Flutter's default font is Roboto for Android if you did not change it other font.

    1. Default Android: Roboto font and for iOS: San Francisco font
    2. Customize https://flutter.dev/docs/cookbook/design/fonts

    Either 1) or 2) these fonts are not available to flutter test by default. Flutter test purposely uses a font called Ahem which is made out of square blocks that you see on your screenshot.

    This is a preview:

    Ahem font square are wayyy bigger than the normal that you are using. Therefore, it causes the RenderFlex overflow error

    Solution

    To achieve a near perfect emulation of your device in flutter test you have to download the font data then load the exact font that you are using.

    To load a font in widget test, you should do inside the testWidgets function or setUp:

    final flamante = rootBundle.load('assets/fonts/Flamante-Roma-Medium.ttf');
          await FontLoader('FlamanteRoma')
            ..addFont(flamante)
            ..load();
    

    Then add this font to the ThemeData before pumping the widget.

     theme: ThemeData(
                  fontFamily: 'FlamanteRoma',
     ),
    

    The final test.dart code is:

    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'package:flutter_test/flutter_test.dart';
    import 'package:example/test/compare_test_size.dart';
    
    void main() {
      testWidgets(
        "Emulate real screen size",
        (WidgetTester tester) async {
          final flamante = rootBundle.load('assets/fonts/Flamante-Roma-Medium.ttf');
          await FontLoader('FlamanteRoma')
            ..addFont(flamante)
            ..load();
    
          // Adjust these to match your actual device screen specs
          final width = 411.4;
          final height = 797.7;
          tester.binding.window.devicePixelRatioTestValue = (2.625);
          tester.binding.window.textScaleFactorTestValue = (1.1);
          final dpi = tester.binding.window.devicePixelRatio;
          tester.binding.window.physicalSizeTestValue = Size(width * dpi, height * dpi);
          await tester.pumpWidget(
            MediaQuery(
              data: MediaQueryData(),
              child: MaterialApp(
                home: TextScaleComparaison(),
                theme: ThemeData(
                  fontFamily: 'FlamanteRoma',
                ),
              ),
            ),
          );
          await expectLater(
            find.byType(TextScaleComparaison),
            matchesGoldenFile("text.png"),
          );
        },
      );
    }
    

    Now re generate the golden test and check the png. You will see real text, not boxes anymore:

    test/test.png

    And don't forget to add the same font in your main.dart

    runApp(
        MaterialApp(
          home: TextScaleComparaison(),
          theme: ThemeData(
            fontFamily: 'FlamanteRoma',
          ),
        ),
      );
    

    And also don't forget to update pubspec.yaml and run flutter pub get

    - family: FlamanteRoma
      fonts:
        - asset: assets/fonts/Flamante-Roma-Medium.ttf
    

    这篇关于Flutter Widget测试无法正确模拟其他屏幕尺寸的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆