flutter 在小部件测试中测试AlertDialog/`showDialog`(“Which:表示未找到,但预期有一个”)

jhiyze9q  于 2023-05-30  发布在  Flutter
关注(0)|答案(2)|浏览(152)

我正在尝试编写一个小部件测试,以确保向用户显示AlertDialog
我有一个小例子来重现这个。当用户手动使用时,小部件会显示AlertDialog,但在小部件测试中无法显示。

我尝试了几件事:

  • 使用不同的方法检索按钮:find.byKeyfind.byIcon
  • 使用不同的方法按下按钮:tester.taptester.press
  • 在按下按钮后使用一些任意延迟:await tester.pumpAndSettle(const Duration(milliseconds: 1000));
  • 检查不同的预期元素:expect(find.byElementType(AlertDialog), findsOneWidget);,将一个不同的图标,例如pokeball和得到它:expect(find.byIcon(Icons.catching_pokemon), findsOneWidget)
  • 设置useDialoguseRootNavigator:false
  • 提示:如果运行flutter run main.dart,它将在设备屏幕上可视地运行测试
  • 技巧2:你可以通过注解掉一些代码来运行应用程序(参见main函数)

简短示例

import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';

const buttonKey = Key("button");
const alertDialogKey = Key("alertDialog");

class MyApp extends StatelessWidget {
  showAppDialog(BuildContext context) async {
    print("Showing app dialog");
    await showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            key: alertDialogKey,
            title: const Text(
              "You can see this dialog, but you can't catch it with WidgetTester.",
            ),
            icon: const Icon(Icons.catching_pokemon),
            actions: [
              TextButton(
                onPressed: () {
                  // Navigator.of(context).pop();
                },
                child: const Text("Oops"),
              ),
            ],
          );
        });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Dialog',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(body: SafeArea(child: Builder(builder: (context) {
        return TextButton(
          key: buttonKey,
          child: const Text("Show dialog"),
          onPressed: () async => await showAppDialog(context),
        );
      }))),
    );
  }
}

void mainTest() {
  testWidgets(
    "When button is pressed, dialog is shown.",
    (tester) async {
      final widget = MyApp();
      await tester.pumpWidget(widget);

      final button = find.byKey(buttonKey);
      expect(button, findsOneWidget);

      await tester.press(button);
      await tester.pumpAndSettle();

      // None of these work:
      expect(find.byKey(alertDialogKey), findsOneWidget);
      expect(find.byIcon(Icons.catching_pokemon), findsOneWidget);
      expect(find.byElementType(AlertDialog), findsOneWidget);
    },
  );
}

void main() {
  // Uncomment to run the app manually
  // runApp(MyApp());
  // Comment out to run the app manually.
  mainTest();
}
rfbsl7qr

rfbsl7qr1#

我需要做两件事

  • 触发await tester.runAsync(() async {})内部的按钮,因为showDialog是一个异步函数。默认情况下,出于性能原因,Flutter在测试中实际上并不运行异步工作。🤓
  • 使用tester.tap而不是tester.press,因为press实际上不会释放按钮,所以**.press不会触发onPressed回调**😈。
void mainTest() {
  testWidgets(
    "When button is pressed, dialog is shown.",
    (tester) async {
      final widget = MyApp();
      await tester.pumpWidget(widget);

      final button = find.byKey(buttonKey);
      expect(button, findsOneWidget);

      await tester.runAsync(() async {
        await tester.tap(button);
//         Or alternatively press then "up":
//         final response = await tester.press(button);
//         await response.up();
      });
      await tester.pumpAndSettle();

      // These all work now
      expect(find.byKey(alertDialogKey), findsOneWidget);
      expect(find.byIcon(Icons.catching_pokemon), findsOneWidget);
      expect(find.byType(AlertDialog), findsOneWidget);
    },
  );
}

**额外提示:**在设备上运行测试,以可视化正在发生的事情。运行flutter run test/name_of_test.dart。这可以帮助您了解问题所在:比如说是AlertDialog没有显示,还是find.byType没有找到AlertDialog

wqlqzqxt

wqlqzqxt2#

我有一个非常类似的问题,所有我需要做的是删除'等待'时,我'showDialog'。这似乎是因为pumpAndSettle在继续之前等待对话框关闭,而实际上它并没有关闭。

相关问题