【问题标题】:How to mock the FirebaseApp in flutter如何在颤动中模拟 FirebaseApp
【发布时间】:2020-12-19 01:19:26
【问题描述】:

我正在尝试测试使用 FirebaseFirestore 的方法,但我无法模拟 FirebaseFirestore.instance 属性。

我正在遵循这些示例:

  1. 初始化内核:https://firebase.flutter.dev/docs/overview#initializing-flutterfire
  2. 使用 Firestore 插件:https://firebase.flutter.dev/docs/firestore/usage

我正在为我的课程使用下面的代码,它运行良好,这意味着 firestoreInstance 已正确加载

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  runApp(
    Main(firebaseApp: Firebase.initializeApp()),
  );
}

class Main extends StatelessWidget {
  final Future<FirebaseApp> firebaseApp;
  const Main({this.firebaseApp});

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: firebaseApp,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.done) {
          final firestoreInstance = FirebaseFirestore.instanceFor(
            app: snapshot.data,
          );
          return MyWidget();
        }
        return CircularProgressIndicator();
      },
    );
  }
}

但是当我运行下面的测试时,我得到了消息:

“在构建 Builder(脏)时引发了以下 FirebaseException: [core/no-app] 没有创建 Firebase 应用“[DEFAULT]” - 调用 Firebase.initializeApp()"


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

class MockFirebaseApp extends Mock implements FirebaseApp {}

void main() {
  FirebaseApp firebaseApp;

  setUp(() async {
    TestWidgetsFlutterBinding.ensureInitialized();
    firebaseApp = MockFirebaseApp();
  });

  group('Main', () {
    testWidgets('Loads my widget', (WidgetTester tester) async {
      await tester.runAsync(() async {
        await tester.pumpWidget(
          Main(firebaseApp: Future.value(firebaseApp)),
        );

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

【问题讨论】:

  • 不,这个链接显示了如何实现这个类,我就是这样做的,它就像一个魅力。我的问题出在单元测试中,因为我不知道如何模拟 Firebase.initializeApp() 方法,在我的描述示例中,我使用 Mockito 来模拟作为 FirebaseApp 对象的调用的返回跨度>
  • 我不确定你模拟 Firebase.initializeApp() 方法是什么意思。虽然 Mockito 非常适合所有目的的模拟,但我想指出还有 Mock Cloud Firestore 可以更接近您对 Firestore 的需求。 Mock Clou Firestore in Flutter documentation
  • 我想要的“模拟 Firebase.initializeApp() 方法”非常简单。我想收到一个 FirebaseApp 实例,当单元测试到达 FirebaseFirestore.instanceFor( app: MOCKED_MY_FIREBASEAPP_INSTANCE, ) 时,Mockito 可以很好地模拟该方法,但它返回的对象在 FirebaseFirestore.instanceFor 方法中不起作用我已经检查过CloudFirestore Mock 项目,也许我可以使用它,但为此,我需要对我的代码进行大量重构。我尝试仅使用它来获取 FirebaseApp 实例,但它也对我不起作用。

标签: firebase unit-testing flutter google-cloud-firestore mocking


【解决方案1】:

我遇到了同样的问题。使用this answer 我找到了解决方案。

  1. https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_auth/firebase_auth/test/mock.dart 的内容复制到一个文件中,您可以将其导入到您的测试中,您需要在其中初始化一个 Firebase 应用。

  2. 在您的 main 函数顶部调用 setupFirebaseAuthMocks(); 以进行所有测试。

  3. 在你的setUpAll函数中,调用await Firebase.initializeApp();(你也可以把它放在setupFirebaseAuthMocks();下的main函数中仍然可以工作)。

现在你应该有一个模拟的 Firebase 应用了。

这是一个完整的例子:

import 'package:flutter/material.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter_test/flutter_test.dart';
import '../lib/authentication/your_auth_using_firebase.dart';
import './mock.dart'; // from: https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_auth/firebase_auth/test/mock.dart



void main() {
  // TestWidgetsFlutterBinding.ensureInitialized(); Gets called in setupFirebaseAuthMocks()
  setupFirebaseAuthMocks();

  setUpAll(() async {
    await Firebase.initializeApp();
  });

  testWidgets('Your Test', (WidgetTester tester) async {
    final YourFirebaseAuthClass authService = YourFirebaseAuthClass();
    // Tests to write
  });
}

【讨论】:

  • 这对我来说效果很好。谢谢加雷斯!
  • 谢谢。不是更干净的测试方法,但它也适用于我。
  • Gareth - 很好的标注,但似乎不适用于应用程序中的 firebase crashlytics,或者至少我在那里遇到了断言错误
【解决方案2】:

也许cloud_firestore_mocks 包对你有用:

为 Cloud Firestore 编写单元测试的假货。实例化一个 MockFirestoreInstance,然后在您的项目中传递它,就好像它是一个 FirestoreInstance。这个伪造的行为类似于 Firestore,只是它只会将状态保存在内存中。为了帮助调试,您可以使用 MockFirestoreInstance.dump() 查看假数据库中的内容。这对于设置数据库的状态很有用,然后检查您的 UI 的行为是否符合您的预期。

文档中的示例:

import 'package:cloud_firestore_mocks/cloud_firestore_mocks.dart';

void main() {
  final instance = MockFirestoreInstance();
  await instance.collection('users').add({
    'username': 'Bob',
  });
  final snapshot = await instance.collection('users').get();
  print(snapshot.documents.length); // 1
  print(snapshot.documents.first['username']); // 'Bob'
  print(instance.dump());
}

【讨论】:

    【解决方案3】:

    认为这是为了将 FutureBuilder 用作树的第一个 Widget o 根小部件,flutter 始终需要 MaterialApp 或其他(现在不记得了)。

    推荐,重构 FutureBuilder -> Wrap whit widget -> MaterialApp(home:FutureBuilder(...

    并检查 MyWidget() 第一个小部件,可能相同的 MaterialApp 出错,但不确定。

    如果您使用路由方法进行导航,请使用 initialRoute。

    好运!

    【讨论】:

    • 我可以这样做,但问题是一样的,我的问题是试图模拟 Firebase.initializeApp() 方法的返回,这意味着我需要模拟一个有效的 FirebaseApp 对象在 FirebaseFirestore.instanceFor( app: MY_MOCKED_OBJECT, )
    猜你喜欢
    • 2022-10-17
    • 1970-01-01
    • 2022-11-22
    • 2022-07-18
    • 2021-07-22
    • 1970-01-01
    • 2020-08-13
    • 2019-07-30
    • 2019-03-17
    相关资源
    最近更新 更多