You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter自定义抽屉与退出按钮测试遇Hive Box打开异常求助

问题:Flutter测试自定义抽屉/退出按钮时出现Hive Box打开异常

我正在为Flutter应用编写自定义抽屉和退出按钮的测试用例,测试代码如下:

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:talawa/constants/custom_theme.dart';
import 'package:talawa/models/mainscreen_navigation_args.dart';
import 'package:talawa/services/graphql_config.dart';
import 'package:talawa/services/navigation_service.dart';
import 'package:talawa/services/size_config.dart';
import 'package:talawa/utils/app_localization.dart';
import 'package:talawa/view_model/main_screen_view_model.dart';
import 'package:talawa/views/main_screen.dart';
import 'package:talawa/widgets/custom_alert_dialog.dart';
import '../../helpers/test_helpers.dart';
import '../../helpers/test_helpers.mocks.dart';
import '../../helpers/test_locator.dart';

class MockBuildContext extends Mock implements BuildContext {}

Widget createHomePageScreen() {
  return MaterialApp(
    locale: const Locale('en'),
    localizationsDelegates: [
      const AppLocalizationsDelegate(isTest: true),
      GlobalMaterialLocalizations.delegate,
      GlobalWidgetsLocalizations.delegate,
    ],
    themeMode: ThemeMode.light,
    theme: TalawaTheme.lightTheme,
    home: MainScreen(
      key: const Key('MainScreen'),
      mainScreenArgs: MainScreenArgs(mainScreenIndex: 0),
    ),
  );
}

void main() {
  testSetupLocator();

  setUp(() {
    registerServices();
    locator<SizeConfig>().test();
    locator<GraphqlConfig>().test();
  });

  group('Exit Button', () {
     testWidgets("Tapping Tests for Exit", (tester) async {
      await tester.pumpWidget(createHomePageScreen());
      await tester.pumpAndSettle();
      tester.binding.window.physicalSizeTestValue = const Size(4000, 4000);
      MainScreenViewModel.scaffoldKey.currentState?.openDrawer();
      await tester.pumpAndSettle();
      final leaveOrg = find.byKey(MainScreenViewModel.keyDrawerLeaveCurrentOrg);
      await tester.tap(leaveOrg);
      await tester.pumpAndSettle();
      final dialogPopUP = verify(
              (locator<NavigationService>() as MockNavigationService)
                  .pushDialog(captureAny),)
          .captured;
      expect(dialogPopUP[0], isA<CustomAlertDialog>());
      // calling success() to have complete code coverage.
      dialogPopUP[0].success();
    });
  });
  group('Custom Drawer Test', () {
    testWidgets("Widget Testing", (tester) async {
      // pumping the Widget
      await tester.pumpWidget(createHomePageScreen());
      await tester.pumpAndSettle();
      // Opening the Drawer so that it can be loaded in the widget tree and built() is called
      await tester.dragFrom(
          tester.getTopLeft(find.byType(MaterialApp)), const Offset(300, 0));
      await tester.pumpAndSettle();
      // getting the Finders for Code Coverage
      expect(find.byKey(const ValueKey("Drawer")), findsOneWidget);
      expect(find.byKey(const ValueKey("Custom Drawer")), findsOneWidget);
      expect(find.text("Selected Organization"), findsOneWidget);
      expect(find.text("Switch Organization"), findsOneWidget);
      final listOfOrgs = find.byKey(const ValueKey("Switching Org"));
      expect(listOfOrgs, findsOneWidget);
      expect(find.byKey(MainScreenViewModel.keyDrawerCurOrg), findsOneWidget);
      expect(find.byKey(MainScreenViewModel.keyDrawerSwitchableOrg),
          findsOneWidget);
      expect(find.byType(UserAccountsDrawerHeader), findsOneWidget);
      expect(find.text("Join new Organization"), findsOneWidget);
      expect(find.text("Leave Current Organization"), findsOneWidget);
      final fromPalisadoes = find.byKey(const ValueKey("From Palisadoes"));
      expect(fromPalisadoes, findsOneWidget);
    });
    testWidgets("Tapping Tests for Org", (tester) async {
      await tester.pumpWidget(createHomePageScreen());
      await tester.pumpAndSettle();
      // Opening the Drawer so that it can be loaded in the widget tree and built() is called
      await tester.dragFrom(
          tester.getTopLeft(find.byType(MaterialApp)), const Offset(300, 0));
      await tester.pumpAndSettle();
      final orgs = find.byKey(const ValueKey("Org"));
      // Atleast One Org should be there
      // ignore: invalid_use_of_protected_member
      expect(orgs.allCandidates.isEmpty, false);
      await tester.tap(orgs.first);
      // Was not required but done for code Coverage
      // Sized
      final sizedbox = find.byKey(const ValueKey("Sized Box Drawer"));
      // ignore: invalid_use_of_protected_member
      expect(sizedbox.allCandidates.isEmpty, false);
    });
    testWidgets("Tapping Tests for Join", (tester) async {
      await tester.pumpWidget(createHomePageScreen());
      await tester.pumpAndSettle();
      tester.binding.window.physicalSizeTestValue = const Size(800, 4000);
      MainScreenViewModel.scaffoldKey.currentState?.openDrawer();
      await tester.pumpAndSettle();
      final joinOrg = find.byKey(MainScreenViewModel.keyDrawerJoinOrg);
      await tester.tap(joinOrg);
      // await tester.pumpAndSettle();
    });
  });

  tearDown(() {
    unregisterServices();
  });
}

测试过程中出现了多个异常,例如open hive Box异常。我并未在当前测试代码中直接使用Hive,想请教问题出在哪里。


解决方法

  • 追踪Hive的间接调用:你测试的MainScreen、MainScreenViewModel,或者registerServices()中注册的服务(比如GraphqlConfig、存储类等),大概率在初始化或运行时间接调用了Hive。比如ViewModel可能从Hive读取用户/组织缓存,或者服务类用Hive存储配置。
  • Mock所有依赖Hive的组件:在测试的setUp阶段,把所有会触发Hive操作的类替换为Mock实现。比如如果有封装Hive的StorageService,要注册MockStorageService代替真实类,并且通过when/thenReturn避免实际Hive调用。
  • 初始化测试版Hive(若必须使用):如果某些逻辑必须依赖Hive,可以在测试前初始化Hive的测试环境:
    setUp(() async {
      await Hive.initFlutter('test_hive_dir');
      await Hive.openBox('test_box');
      // 其他setup逻辑
    });
    
    tearDown(() async {
      await Hive.deleteFromDisk();
      await Hive.close();
    });
    
  • 检查服务注册逻辑:查看testSetupLocator()和registerServices()的实现,确保所有依赖Hive的服务都被Mock,而非使用真实实例。比如GraphqlConfig如果内部用了Hive存储token,就要Mock它对应的方法。
  • Mock ViewModel的Hive相关逻辑:如果MainScreenViewModel在初始化时读取Hive数据,需要在测试前Mock这些方法,比如:
    when(mockMainScreenViewModel.loadOrgData()).thenAnswer((_) async => []);
    

内容的提问来源于stack exchange,提问作者Indresh Goswami

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 22:55:04