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

Firebase Storage相关Widget测试失败问题排查求助

问题分析与解决方案

核心问题点

  • Mock Firebase Storage 未注入Widget:测试中创建的MockFirebaseStorage实例未被Widget使用,Widget的getUserImages方法直接调用FirebaseStorage.instanceFor获取默认实例,导致Storage操作无法命中mock数据。
  • MockUserRepository 无用户数据:测试用的mockUserRepo未填充user属性(如firstName、birthdate、about),页面渲染后不会显示目标文本。
  • State 更新逻辑缺失:getUserImages修改类成员userImages但未调用setState()触发UI刷新;同时FutureBuilder未使用snapshot.data,异步操作完成后UI不会自动更新。
  • 用户ID不匹配:测试中上传图片的路径是"123/image-0.jpg",但mockUserRepo的userId未对应设置为"123",导致查找Storage路径错误。

分步修复方案

1. 注入Mock Firebase Storage

使用firebase_core_mocks配合mockito替换全局Firebase实例,确保Widget使用测试中的mock对象:

// 测试开头初始化mock Firebase环境
setupFirebaseAuthMocks();

testWidgets('Profile screen displays proper data', (WidgetTester tester) async {
  await Firebase.initializeApp();
  final mockStorage = MockFirebaseStorage();
  
  // 上传测试图片到mock Storage
  final imageZeroRef = mockStorage.ref().child("123/image-0.jpg");
  final fileZero = await rootBundle.load("../../assets/Welcome.png");
  await imageZeroRef.putData(fileZero.buffer.asUint8List());

  // 替换FirebaseStorage.instanceFor的默认实现
  when(FirebaseStorage.instanceFor(bucket: anyNamed('bucket'))).thenReturn(mockStorage);

  // 初始化带用户数据的mock仓库
  final mockUserRepo = MockUserRepository();

  await tester.pumpWidget(ProviderScope(
    overrides: [
      userProvider.overrideWith((ref) => mockUserRepo),
    ],
    child: const MaterialApp(home: UserProfileScreen()),
  ));

  await tester.pumpAndSettle(); // 等待所有异步操作完成

  final firstNameFinder = find.text("Bob, 27");
  expect(firstNameFinder, findsOneWidget);

  final aboutFinder = find.text("About Bob");
  expect(aboutFinder, findsOneWidget);
});

2. 完善MockUserRepository的用户数据

确保mock仓库预填充必要的用户信息:

class MockUserRepository extends Mock implements UserRepository {
  @override
  final String userId = "123"; // 匹配Storage路径的用户ID

  @override
  User? user = User(
    firstName: "Bob",
    birthdate: DateTime.now().subtract(const Duration(days: 27*365)), // 生成27岁的出生日期
    about: "About Bob",
  );
}

3. 修复Widget的State更新逻辑

修改getUserImages和FutureBuilder,确保异步操作完成后UI自动刷新:

// 修改getUserImages,返回新列表而非修改类成员
Future<List<String>> getUserImages(String userId) async {
  final storageRef = FirebaseStorage.instanceFor(bucket: "gs://some-bucket").ref();
  List<String> images = List.filled(6, "");

  try {
    for (var i = 0; i < 6; i++) {
      final imageRef = storageRef.child("$userId/image-$i.jpg");
      final downloadUrl = await imageRef.getDownloadURL();
      images[i] = downloadUrl;
    }
    return images;
  } on FirebaseException catch (err, stackTrace) {
    Logger().e("unable to download profile images for user with id $userId \n Error Code: ${err.code} \n Error Message: ${err.message} \n $stackTrace");
  }

  return images;
}

// 修改FutureBuilder的builder逻辑,使用snapshot数据更新UI
FutureBuilder(
  future: getUserImages(userId),
  builder: (BuildContext context, AsyncSnapshot<List<String>> snapshot) {
    if (snapshot.connectionState != ConnectionState.done) {
      return buildLoadingPage();
    }
    final userImages = snapshot.data ?? List.filled(6, "");
    return ListView(
      cacheExtent: 1000,
      children: [
        userImages[0] != ""
            ? ImageCard(
                imageUrl: userImages[0],
                text: viewUser != null 
                    ? "${viewUser.user?.firstName}, ${determineUserAge(viewUser.user!.birthdate!)}" 
                    : "${authUser.user?.firstName}, ${determineUserAge(authUser.user!.birthdate!)}",
              )
            : const SizedBox(),
        // 其余UI元素保持不变
      ],
    );
  },
),

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 17:47:55