Flutter widget 测试选择另一个项目时不会触发 DropdownButton.onChanged

2023-11-23

我正在编写一个 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 的行为有什么魔力?


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

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

测试时的一些提示。

  1. DropdownButton 由按钮的“IndexedStack”和菜单项列表的普通堆栈组成。
  2. 不知何故,您分配的键和文本DropDownMenuItem被赋予上述堆栈中的两个小部件。
  3. 点击时选择返回的小部件列表中的最后一个元素。
  4. 此外,下拉按钮需要一些时间来制作动画,所以我们调用tester.pump是颤振参考测试中建议的两倍。
  5. The value的财产DropdownButton不会自动更改。它必须设置使用setState。所以你的最后一行断言是错误的,除非你将测试包装在一个StatefulBuilder like 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'));
      
    });
  });
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter widget 测试选择另一个项目时不会触发 DropdownButton.onChanged 的相关文章

随机推荐

  • IE9 中缩小后的图像质量较差

    我注意到 IE9 以非常低的质量渲染缩小尺寸的图像 如果我在 200x150 IMG 标签中显示 800x600 jpg 图像 则 IE9 中的结果非常令人失望 同一页面在 IE8 和 Chrome 中显示完美 IE7也可以 只要我用CSS
  • linq where 列表包含列表中的任何内容

    使用 linq 如何检索其属性列表与另一个列表匹配的项目列表 以这个简单的例子和 伪代码为例 List
  • :app:assembleRelease 和 assembleRelease 之间的区别

    我的 android 项目中有多个模块 如果我制作一个发行版APK app assembleRelease它可以工作 但是当我用以下命令发布 apk 时assembleRelease它一直显示错误 我知道我的代码中有错误 但这不是我要质疑的
  • 为什么 Haskell 中不需要工厂模式? OOP 中的模式解决的需求在 Haskell 中是如何解决的?

    我读了这个问题有关抽象工厂模式 但唯一的答案是尝试emulate在 Haskell 中就像在 OOP 语言中一样 尽管前言是这样的在 Haskell 中你不需要它 另一方面 我的目的并不是要在像 Haskell 这样的函数式语言上强制采用特
  • 如何在youtube embed api中监听seek事件

    您好 我正在使用 youtube iframe 嵌入 API 我想跟踪用户的搜索视频事件 请帮助我如何跟踪这个 没有简单的方法可以单独使用 api 来跟踪事件 你可以做的是间隔运行一个javascript函数并检查测量的时间差是否与预期的不
  • Rails 可选 /:locale 路线

    我正在尝试为我的 Rails 应用程序设置一个路由系统 该系统允许将可选路由 locale 允许到网站的底部 所以或多或少 en home 将转到与 home 相同的页面 en people gt people 我遇到的唯一问题是在路由配置
  • GoogleCertificatesRslt:Kotlin Android 应用程序中不允许

    我正在开发一个使用 Kotlin 作为开发语言的 Android 应用程序 该应用程序显示地图并应该加载标记 但是 地图会加载 但标记不会加载 我收到安全异常GoogleCertificatesRslt not allowed我发现这可能是
  • 检测前景窗口何时发生变化

    我知道哪个使用GetForegroundWindow函数我可以获取当前活动窗口句柄 但是现在i want to detect when the active window of any application changes become
  • QTabWidget 大小取决于当前选项卡

    I ve a QTabWidget 其中包含不同高度的小部件 它们的宽度是固定的 但是 默认实现QTabWidget选择最大的部件的高度作为自己的高度 我想知道是否有一种 可能快速 的方法来改变大小QTabWidget取决于其当前选项卡 以
  • 删除 Activity 作为默认启动器

    我将我的活动设置为默认启动器来拦截主页按钮点击 如下所示
  • AngularJS 中的滚动事件

    我有一个带有滚动条的 div 现在我想获取一个事件 每次用户滚动时都会触发该事件 这在 AngularJS 中可能吗 还是我必须使用 jQuery Edit 到目前为止我想出了以下内容 JS directive scroll functio
  • 没有名为“fbprophet”的模块?

    我尝试按照以下说明在 Ubuntu 上的 Anaconda 中安装 Facebook Prophet https facebook github io prophet docs installation html installation
  • pip 和 conda 之间的实际区别

    我看到了有关 pip 和 conda 之间差异的其他问题 但我还不清楚 请在标记为重复之前考虑这一点 如果我跑pip install seaborn and conda install seaborn我会得到同样的结果吗 我可以跑pip i
  • 更好的错误处理[重复]

    这个问题在这里已经有答案了 Here https github com astaxie build web application with golang blob master en 11 1 md描述了如何根据 http 包使用自定义路
  • IPython 导入失败和 python sys.path 一般情况

    我正在关注这个post让一个 ipython 统治所有 virtualenvs 据我了解 这篇文章的主要思想是 当在 virtualenv 中时 ipython 找不到它的模块 a virtualenv me pc ipython Trac
  • 从服务器 HTTPS 接收并验证证书 - android

    我正在通过 https 从 Android 客户端调用 Web 服务 我必须验证从服务器端收到的证书 我怎么做 目前 这是我用来调用网络服务的代码 private static String SendPost String url Arra
  • 如何在 Jekyll 中链接到没有 html 扩展名的 page.url 页面?

    我正在 Jekyll 中建立一个网站 为了删除帖子中的 html 扩展名 我将以下内容添加到 config yml permalink kb title 为了从页面中删除 html 扩展名 我为每个页面创建了文件夹 并在每个页面文件夹中放置
  • 如何有条件地为表格单元格中的背景着色?

    我正在渲染一个表格p 数据表 PrimeFaces 我想要做的是根据单元格内容的值对单元格的背景进行着色 这与为行或列着色不同 它是单个单元格 首先是CSS问题 如果我这样做
  • 从 HTML 页面源下载图像文件

    我正在编写一个抓取工具 用于从 HTML 页面下载所有图像文件并将它们保存到特定文件夹中 所有图像都是 HTML 页面的一部分 下面是一些代码 用于从提供的 URL 下载所有图像 并将它们保存在指定的输出文件夹中 您可以根据自己的需要对其进
  • Flutter widget 测试选择另一个项目时不会触发 DropdownButton.onChanged

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