Flutter小部件单元测试引发未找到方向性小部件

时间:2020-01-28 10:13:47

标签: unit-testing flutter dart widget

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

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,),但是那是一个不好的解决方案,它不适用于行。

2 个答案:

答案 0 :(得分:1)

好的,这是解决方法。

您必须使用以下方法包装小部件:

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

答案 1 :(得分:0)

在现实世界中的Flutter应用中,先要准备好要测试的Widget可能取决于一堆框架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小部件依赖于状态管理的提供程序,它使用本地化,并且应用程序使用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