Scenario

我是小部件测试和GoRouter的新手.我有一个非常简单的测试用例:

  • 有两个屏幕- LoginPage作为第一个屏幕加载,和CheckoutPage
  • LoginPage有一个按钮.一旦我点击它,我就会被带到CheckoutPage号公路.

我正在使用GoRouter进行导航.

Code

以下是main.dart年度MaterialApp的设置方式:

MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: GoRouteInformation.router,
            title: "Neon Student",
          ),

以下是routerConfig个和RouteNames个班级:

100

class GoRouteInformation {
  static final GoRouter router = GoRouter(
    routes: [
      GoRoute(
        path: '/',
        name: RouteNames.login,
        builder: (context, state) => const LoginPage(),
        routes: [
          GoRoute(
            path: 'checkout',
            name: RouteNames.checkout,
            builder: (context, state) => const CheckoutPage(),
          ),
        ],
      ),
    ],
  );
}

100

class RouteNames {
  static const String login = 'login';
  static const String checkout = 'checkout';
}

以下是loginpage_test.dart中的代码:

testWidgets('Navigates from LoginPage to CheckoutPage', (WidgetTester tester) async {
    await tester.pumpWidget(const MainApp());
    await tester.pumpWidget(const MaterialApp(home: LoginPage()));

    expect(find.byType(LoginSection), findsOneWidget);
    expect(find.byType(SplitDivider), findsOneWidget);

    Finder subscribeButton = find.byKey(const ValueKey('Subscribe'));
    expect(subscribeButton, findsOneWidget);

    await tester.tap(subscribeButton);
    await tester.pumpAndSettle();

    expect(find.byType(CheckoutPage), findsOneWidget);
  });

EDIT:这是我的main.dart

void main() {
  runApp(const MainApp());
}

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: const Size(428, 926),
      minTextAdapt: true,
      splitScreenMode: true,
      builder: (_, child) {
        return GestureDetector(
          onTap: () {
            FocusManager.instance.primaryFocus?.unfocus();
          },
          behavior: HitTestBehavior.opaque,
          child: MaterialApp.router(
            debugShowCheckedModeBanner: false,
            routerConfig: GoRouteInformation.router,
            title: "Neon Student",
          ),
        );
      },
    );
  }
}

Problem

当我运行flutter test时,我得到以下错误:

  1. The following assertion was thrown while handling a gesture: No GoRouter found in context 'package:go_router/src/router.dart': Failed assertion: line 507 pos 12: 'inherited != null'
  2. The following TestFailure was thrown running a test: Expected: exactly one matching candidate Actual: _TypeWidgetFinder:<Found 0 widgets with type "CheckoutPage": []> Which: means none were found but one was expected

Request

我想知道我的小部件测试代码中有什么错误导致测试失败,以及如何纠正它.

推荐答案

await tester.pumpWidget(const MainApp());
await tester.pumpWidget(const MaterialApp(home: LoginPage()));

这就是问题所在.它有两个问题:

  1. 第一个PUMP基本上被忽略,因为您需要PUMP另一个小部件.在给定时刻,"沙箱"中只能有一个小部件.
  2. 你抽出一个裸露的MaterialApp,没有路由.

要使路由在您的测试中可用,您必须像在MainApp中所做的那样,将其传递给被激发的应用程序:

await tester.pumpWidget(
  MaterialApp.router(
    routerConfig: GoRouteInformation.router,
    home: const LoginPage(),
  ),
);

您可以在test/目录中创建一个实用小部件TestApp,该小部件将在小部件测试中重复使用,它将拥有小部件正常运行所需的所有环境.

这解释了您收到的错误:

处理手势时引发以下断言:在上下文‘Package:go_router/src/router.dart’中找不到GoRouter:失败的断言:第507行位置12:‘继承!=NULL’

这意味着GoRouter.of(context)LoginPage上方的窗口小部件树中找不到路由.这是因为加油站的MaterialApp没有路由.

Flutter相关问答推荐

Cupertino Buttino SheetAction on按下可触发加载指示器,然后勾选并延迟

Flutter:InteractiveViewer中可伸缩SVG背景上的定位小部件不对齐

如何为Android 12及以上设备以及Android 11及以下设备动态处理Splash Screen?如果可能的话没有包裹

在创建肘部并使用冻结时,无法使用中的Copy With方法

Ffltter:发布版本中的Path NotFoundException

轻松本地化包翻译在底部导航栏项目标签Flutter 翼dart 中不起作用

在Flutter 中创建自定义形状

当我转到其他屏幕并按下后退按钮时,屏幕将不会刷新

如何在flutter中使用youtube_explod_start加载下一页

在 Flutter 中解码 BLE 设备负载

如何计算 Firestore 集合中的文档数量?

MediaQuery 在不同手机上不一致

如何让小部件根据小部件的大小构建不同的布局?

我怎样才能一次只选中一个复选框?

如何在 Flutter 中使用简写 IF 禁用单选按钮?

无法将参数类型Future Function(String?)分配给参数类型void Function(NotificationResponse)?

如何在手势检测器中获得涟漪效应

运行Flutter 测试时出现 FirebaseAppPlatform.verifyExtends 错误

Flutter Desktop,如何获取windows用户配置文件名称?

在 Flutter Bloc 中具有称为 status 的属性的一种状态或不同的状态,哪个更可取?