【问题标题】:Flutter widget test does not trigger DropdownButton.onChanged when selecting another itemFlutter 小部件测试在选择另一个项目时不会触发 DropdownButton.onChanged
【发布时间】:2021-02-05 22:20:07
【问题描述】:

我正在编写一个 Flutter Web 应用程序,并向我的代码库添加一些小部件测试。我很难让 flutter_test 按预期工作。我当前面临的问题是尝试在 DropdownButton 中选择一个值。

下面是重现问题的完整小部件测试代码:

void main() {
  group('description', () {
    testWidgets('description', (WidgetTester tester) async {
      await tester.pumpWidget(MaterialApp(
        home: Card(
          child: Column(
            children: [
              Expanded(
                child: DropdownButton(
                  key: Key('LEVEL'),
                  items: [
                    DropdownMenuItem<String>(
                      key: Key('Greater'),
                      value: 'Greater',
                      child: Text('Greater'),
                    ),
                    DropdownMenuItem<String>(
                      key: Key('Lesser'),
                      value: 'Lesser',
                      child: Text('Lesser'),
                    ),
                  ],
                  onChanged: (value) {
                    print('$value');
                  },
                  value: 'Lesser',
                ),
              )
            ],
          ),
        ),
      ));

      expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
          equals('Lesser'));

      await tester.tap(find.byKey(Key('LEVEL')));

      await tester.tap(find.byKey(Key('Greater')));
      await tester.pumpAndSettle();

      expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
          equals('Greater'));
    });
  });
}

这个测试在最终期望上失败了——expect(widget.value, equals('Greater'));

onChanged 回调永远不会被调用,正如我在调试器中看到的那样,或者在输出中寻找我的打印语句。

测试 DropdownButton 的行为有什么魔力?

【问题讨论】:

    标签: flutter flutter-web flutter-test


    【解决方案1】:

    在测试时,在任何与用户交互相关的代码之后添加tester.pump() 调用很重要。

    下拉按钮的测试与通常的小部件略有不同。对于所有情况,最好参考here,这是对下拉按钮的实际测试。

    测试时的一些提示。

    1. DropdownButton 由按钮的“IndexedStack”和菜单项列表的普通堆栈组成。
    2. 不知何故,您为DropDownMenuItem 分配的键和文本被赋予了上述堆栈中的两个小部件。
    3. 点击时选择返回的小部件列表中的最后一个元素。
    4. 此外,下拉按钮需要一些时间来制作动画,因此我们调用 tester.pump 两次,正如 Flutter 中提到的测试中所建议的那样。
    5. DropdownButtonvalue 属性不会自动更改。它必须使用setState 进行设置。因此,您的最后一行断言是错误的,除非您将测试包装在 StatefulBuilder 中,例如 here,否则将无法正常工作。

    有关如何使用DropDownButton的更多详细信息,请查看post

          
    import 'package:flutter/material.dart';
    import 'package:flutter_test/flutter_test.dart';
    
    void main() {
      group('description', () {
        testWidgets('description', (WidgetTester tester) async {
          String changedValue = 'Lesser';
          await tester.pumpWidget(MaterialApp(
            home: Scaffold(
              body: Center(
                child: RepaintBoundary(
                  child: Card(
                    child: Column(
                      children: [
                        Expanded(
                          child: DropdownButton(
                            key: Key('LEVEL'),
                            items: [
                              DropdownMenuItem<String>(
                                key: ValueKey<String>('Greater'),
                                value: 'Greater',
                                child: Text('Greater'),
                              ),
                              DropdownMenuItem<String>(
                                key: Key('Lesser'),
                                value: 'Lesser',
                                child: Text('Lesser'),
                              ),
                            ],
                            onChanged: (value) {
                              print('$value');
                              changedValue = value;
                            },
                            value: 'Lesser',
                          ),
                        )
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ));
    
          expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
              equals('Lesser'));
          // Here before the menu is open we have one widget with text 'Lesser'
          await tester.tap(find.text('Lesser'));
          // Calling pump twice once comple the the action and
          // again to finish the animation of closing the menu.
          await tester.pump();
          await tester.pump(Duration(seconds: 1));
    
          // after opening the menu we have two widgets with text 'Greater'
          // one in index stack of the dropdown button and one in the menu .
          // apparently the last one is from the menu.
          await tester.tap(find.text('Greater').last);
          await tester.pump();
          await tester.pump(Duration(seconds: 1));
    
          /// We directly verify the value updated in the onchaged function.
          expect(changedValue, 'Greater');
    
          /// The follwing expectation is wrong because you haven't updated the value
          ///  of dropdown button.
          // expect((tester.widget(find.byKey(Key('LEVEL'))) as DropdownButton).value,
          //     equals('Greater'));
          
        });
      });
    }
    
    

    【讨论】:

    • 我编辑了上面的代码以显示我已经添加了对 tester.pump() 的调用,但测试仍然失败,因为 DropdownButton 的值仍然是“Lesser”。
    • 你用的是哪个版本的flutter。?您能否也发布颤振医生摘要,以便尝试重现。在我的情况下,它失败了,因为不知何故 finder 找到了多个具有相同键的小部件。
    猜你喜欢
    • 2022-08-03
    • 2021-10-30
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 2018-01-04
    • 1970-01-01
    • 2015-03-16
    • 1970-01-01
    相关资源
    最近更新 更多