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

Flutter测试中添加Firestore实时监听器后测试提前终止无法执行用例

问题根因

你的代码出现该问题的核心原因有3个:

  1. Dart测试框架的测试用例是同步收集的,你在Firestore的异步回调中动态定义testWidgets,测试框架执行完同步代码时还没有收集到任何测试用例,会直接判定无测试任务结束进程,根本等不到Firestore的回调触发。
  2. 主函数中你用then处理Firebase初始化,没有等待初始化完成就继续执行,同时重复初始化了两个WidgetBinding,存在逻辑隐患。
  3. 没有设置阻塞逻辑让测试进程挂起等待Firestore的事件推送,同步代码执行完成后进程直接退出,监听器的回调没有机会执行。

修复方案

1. 修正主函数逻辑

删除重复的Binding初始化,用await等待Firebase初始化完成,提前定义固定的测试用例,不要动态注册:

void main() async {
  // 优先初始化测试绑定,避免异步main执行异常
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();
  setupLocator();
  // 等待Firebase初始化完成,不要用then异步处理
  await Firebase.initializeApp();
  final testCoordinator = ApplicationTestCoordinator();

  group('TEST COORDINATOR', () {
    // 提前定义测试用例,在内部等待测试任务触发
    testWidgets("INTEGRATION TESTS", (tester) async {
      await testCoordinator.waitForTestTasks(tester).timeout(
        const Duration(minutes: 30), // 按需调整最长等待时间
        onTimeout: () => throw Exception("等待测试任务超时"),
      );
    });
  });
}

2. 重写ApplicationTestCoordinator逻辑

用Completer阻塞测试进程,直到监听到Firestore事件执行完测试逻辑后再结束测试:

class ApplicationTestCoordinator {
  final Completer<void> _testCompleter = Completer();

  Future<void> waitForTestTasks(WidgetTester tester) async {
    print(">>>>>>>>>>>>>>>>>>>>>>>> 1");
    try {
      print(">>>>>>>>>>>>>>>>>>>>>>>> 2");
      final snapshots = FirebaseFirestore.instance
          .collection('_integration_tests')
          .snapshots();
      print(">>>>>>>>>>>>>>>>>>>>>>>> 3");
      
      snapshots.listen((event) async {
        List<DocumentChange> changedDocs = event.docChanges;
        for (int index = 0; index < changedDocs.length; index++) {
          final docChange = changedDocs[index];
          final documentID = docChange.doc.id;
          final documentData = docChange.doc.data() ?? {};
          if (docChange.type == DocumentChangeType.added) {
            print("ApplicationTestCoordinator >> document added:$documentID");
            tester.printToConsole("hello");
            // 运行目标应用
            app.main();
            await tester.pumpAndSettle(const Duration(seconds: 6));
            // 执行登录测试逻辑
            await login.login(tester);
            // 单任务测试执行完成后结束阻塞,多任务可等全部执行完再调用complete
            if(!_testCompleter.isCompleted) _testCompleter.complete();
          }
        }
      }, onError: (e, stack) {
        print("ERRORRRRR>>>>>>>>>>>>>>>>>>>>>>>>");
        print(e.toString());
        print(stack);
        if(!_testCompleter.isCompleted) _testCompleter.completeError(e, stack);
      });
      print(">>>>>>>>>>>>>>>>>>>>>>>> 4");
      // 阻塞等待测试任务执行完成
      await _testCompleter.future;
    } catch (e, stack) {
      print("ERRORRRRR>>>>>>>>>>>>>>>>>>>>>>>>");
      print(e.toString());
      print(stack);
      rethrow;
    }
  }
}

注意事项

  • Dart测试框架不支持动态注册测试用例,所有testWidgets必须在同步执行阶段提前定义,只能在测试用例内部等待异步事件触发测试逻辑
  • IntegrationTestWidgetsFlutterBinding已经包含WidgetsFlutterBinding的全部功能,不需要重复初始化
  • 按需调整超时时间,避免长时间等待测试任务时测试被系统强制结束
  • 如果需要执行多个测试任务,可以调整Completer的触发逻辑,统计所有待执行任务完成后再调用complete

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 05:57:02