How to mock the FirebaseApp in flutter

6,083

Solution 1

I had the same problem. Using this answer I found the solution.

  1. Copy the contents of: https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_auth/firebase_auth/test/mock.dart into a file, that you can import into your tests, where you need to initialize a Firebase app.

  2. Call setupFirebaseAuthMocks(); at the top of your main function for all your tests.

  3. In your setUpAll function, call await Firebase.initializeApp(); (You can also put this in your main function under setupFirebaseAuthMocks(); will still work).

Now you should have a mocked Firebase app.

Here is a full example:

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
  });
}

Solution 2

Maybe the cloud_firestore_mocks package is useful for you:

Fakes to write unit tests for Cloud Firestore. Instantiate a MockFirestoreInstance, then pass it around your project as if it were a FirestoreInstance. This fake acts like Firestore except it will only keep the state in memory. To help debug, you can use MockFirestoreInstance.dump() to see what's in the fake database. This is useful to set up the state of your database, then check that your UI behaves the way you expect.

Example from the docs:

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());
}
Share:
6,083
Edson Dias
Author by

Edson Dias

Updated on December 18, 2022

Comments

  • Edson Dias
    Edson Dias over 1 year

    I am trying to test a method that uses FirebaseFirestore but I am not able to mock the FirebaseFirestore.instance property.

    I am following these examples:

    1. Initializing the core: https://firebase.flutter.dev/docs/overview#initializing-flutterfire
    2. Using the firestore plugin: https://firebase.flutter.dev/docs/firestore/usage

    I am using the code below for my class and it is working well, which means the firestoreInstance is loaded correctly

    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();
          },
        );
      }
    }
    

    But when I run the test below I got the message:

    "The following FirebaseException was thrown building Builder(dirty): [core/no-app] No Firebase App '[DEFAULT]' has been created - call 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);
          });
        });
      });
    }
    
    
  • Edson Dias
    Edson Dias over 3 years
    I can do this, but the problem will be the same, my problem is trying to mock the return of the Firebase.initializeApp() method, which means, I need to mock a FirebaseApp object that works in FirebaseFirestore.instanceFor( app: MY_MOCKED_OBJECT, )
  • William Terrill
    William Terrill over 3 years
    This worked well for me. Thank you Gareth!
  • Adrien Arcuri
    Adrien Arcuri about 3 years
    Thank you. Not the cleaner way to test it but it works for me too.
  • nAndroid
    nAndroid about 3 years
    Gareth - great callout but doesn't seem to work with firebase crashlytics in the app, or at least i'm getting assertion errors there
  • martinseal1987
    martinseal1987 over 2 years
    thanks this does give me a good start but also firebase messaging throws MissingPluginException(No implementation found for method Messaging#startBackgroundIsolate on channel plugins.flutter.io/firebase_messaging)
  • masus04
    masus04 about 2 years
    Great Start, thank you. Is there any way to cleanly import the mocks?