【问题标题】:Flutter widget unittests throws No Directionality widget foundFlutter 小部件单元测试抛出未找到方向性小部件
【发布时间】:2020-01-28 10:13:47
【问题描述】:

我尝试对自己的小部件进行单元测试:

testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
  var text = "abc";
  var label = "def";

  await tester.pumpWidget(LabeledTextWidget(
    text,
    label: label,
  ));

  final textFinder = find.text(text);
  final labelFinder = find.text(label);

  expect(textFinder , findsOneWidget);
  expect(labelFinder, findsOneWidget);
});

这是小部件代码:

class LabeledTextWidget extends StatelessWidget {
  final String text;
  final String label;
  LabeledTextWidget(this.text, {this.label});

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
         Text(label,style: Theme.of(context).textTheme.caption,),
         Text(text),
         ],
    );
  }

测试总是抛出异常:

...
No Directionality widget found.
RichText widgets require a Directionality widget ancestor.
The specific widget that could not find a Directionality ancestor was:
RichText
...

我可以通过向所有文本小部件添加文本方向来避免此错误。 (textDirection: TextDirection.ltr,),但这是一个糟糕的解决方案,它不适用于行。

【问题讨论】:

    标签: unit-testing flutter dart widget


    【解决方案1】:

    好的,这就是解决方案。

    你必须用这个包装小部件:

    Directionality(
      child: MediaQuery(
        data: MediaQueryData(),
        child: LabeledTextWidget(this.text, {this.label}),
      ),
      textDirection: TextDirection.ltr,
    );
    

    【讨论】:

      【解决方案2】:

      在现实世界中的 Flutter 应用程序中,被测试的 Widget 可能依赖于一大堆应该在它之前的框架小部件,您可能会遇到许多错误:

      未找到方向性小部件、未找到 MaterialLocalizations、未找到材质小部件、无叠加层等。

      最好的方法是消化main.dart 入口点并提取最低限度(通过反复试验)。这是我的 pumpWidget 示例,我创建并包装了目标 OnlineDictionaries 小部件:

        await tester.pumpWidget(
          MultiProvider(
            providers: [
              ChangeNotifierProvider<OnlineDictionaryManager>(
                create: (context) => OnlineDictionaryManager(FakeOnlineRepo()),
              )
            ],
            child: MaterialApp(
              localizationsDelegates: [
                GlobalMaterialLocalizations.delegate,
                GlobalWidgetsLocalizations.delegate,
                GlobalCupertinoLocalizations.delegate,
              ],
              supportedLocales: [
                const Locale('en', ''),
                const Locale('be', ''),
                const Locale('ru', ''),
              ],
              initialRoute: '/',
              routes: {'/': (context) => Scaffold(body: OnlineDictionaries())},
            ),
          ),
        );
      

      请注意,OnlineDictionaries 小部件依赖 Providers 进行状态管理,它使用本地化并且应用使用 Overlays/Navigator(由 initialRouteroutes 属性解决)。

      之后,您可以操作小部件(例如,检查是否显示负载指示器以及如果清除 TextFormField 是否显示错误消息):

        await tester
            .pump(Duration(milliseconds: 10)); // let progress indicator appear
      
        expect(find.byType(LinearProgressIndicator), findsOneWidget);
      
        await tester.pumpAndSettle();
      
        var field = find.byType(TextFormField);
      
        expect(field, findsOneWidget);
      
        await tester.enterText(find.byType(TextFormField), '');
      
        await tester.pumpAndSettle(Duration(milliseconds: 100));
      
        final errorFinder = find.text('URL can\'t be empty');
      
        expect(errorFinder, findsOneWidget);
      

      这是一个完整的示例(还包括 Mockito 和模拟 SharedPreferences):https://github.com/maxim-saplin/dikt/blob/master/test/ui_dictionaries_test.dart

      【讨论】:

        猜你喜欢
        • 2019-10-01
        • 2018-11-06
        • 1970-01-01
        • 2021-02-04
        • 2022-12-12
        • 2021-05-09
        • 2019-02-25
        • 2018-07-07
        • 1970-01-01
        相关资源
        最近更新 更多