easy_mock_firebase
Firebase test fakes for Flutter widget tests. Independent helpers, each installed inside a test (they register their own teardown):
import 'package:easy_mock_firebase/easy_mock_firebase.dart';
mockFirebaseCore.init()
A drop-in for the official setupFirebaseCoreMocks() that also seeds the
plugin constants some Firebase plugins read before their platform delegate is
built. Notably, Crashlytics asserts isCrashlyticsCollectionEnabled != null in
instanceFor — the official mock leaves that empty, so any Crashlytics call
throws an assertion error a platform fake can't intercept. Use this instead of
setupFirebaseCoreMocks() (before Firebase.initializeApp()) whenever the boot
touches Crashlytics:
mockFirebaseCore.init(); // in place of setupFirebaseCoreMocks()
await Firebase.initializeApp();
mockFirebaseCrashlytics.init();
mockFirebaseAppCheck.init();
mockFirebaseAppCheck.init()
Stubs the Firebase App Check pigeon channel (FirebaseAppCheckHostApi),
keeping the real MethodChannelFirebaseAppCheck Dart. Without it, activate()
awaits an unmocked pigeon channel that only settles on the real event loop, so
the fake test clock hangs (same failure as Firebase Performance). activate /
setTokenAutoRefreshEnabled resolve to void; getToken returns a dummy token;
registerTokenListener replies null, which the plugin swallows, so no live
token EventChannel is opened.
mockFirebaseCrashlytics.init()
Stubs the plugins.flutter.io/firebase_crashlytics MethodChannel via
easy_mock_channel, so the real MethodChannelFirebaseCrashlytics Dart runs but
log / recordError / … never reach the native side. Needs no Firebase.app(),
so it installs with the other mocks before the boot. Still requires
mockFirebaseCore.init() (above) — the platform interface asserts
isCrashlyticsCollectionEnabled in instanceFor, before any channel call. The
boot itself only tears off recordFlutterFatalError, so it never touches
Crashlytics; this covers the case where an error is actually routed to it.
mockFirebasePerformance.init()
Stubs the Firebase Performance pigeon channel (HttpMetric /Trace
start/stop). Without it, the Dio performance interceptor's await metric.start()
is routed to the real platform messenger and only completes on the real event
loop — forcing tests to use runAsync. With it, those calls resolve on the fake
clock, so the whole HTTP flow settles under pump / pumpAndSettle.
mockFirebaseRemoteConfig.init()
Installs an in-memory FirebaseRemoteConfigPlatform, keeping the real
firebase_remote_config Dart logic. Drive values through mockFirebaseRemoteConfig:
mockFirebaseRemoteConfig.setRemoteValues({'show_wallet': true}); // before launching the app
mockFirebaseRemoteConfig.pushUpdate({'show_wallet': false}); // emit an onConfigUpdated event
The app must still run its own Remote Config init (setDefaults /
fetchAndActivate) so the active cache the generated getters read is populated.
mockFirebaseMessaging.init()
Stubs the plugins.flutter.io/firebase_messaging MethodChannel (a plain
channel, unlike Performance/Remote Config which are pigeon) via
easy_mock_channel, keeping the real firebase_messaging Dart logic. Installs
default-happy replies — permission authorized, a fake FCM/APNs token, no initial
message — and lets you tweak them:
mockFirebaseMessaging.init();
mockFirebaseMessaging.deny(); // requestPermission → denied
mockFirebaseMessaging.token('tok-123'); // getToken() → 'tok-123'
mockFirebaseMessaging.initialMessage({...}); // getInitialMessage() → a RemoteMessage
// assert the app asked for permission:
expect(mockFirebaseMessaging.verify('Messaging#requestPermission'), hasLength(1));
Covers the methods the app hits during boot/init (requestPermission,
getToken, getInitialMessage, setForegroundNotificationPresentationOptions,
getAPNSToken, …). Use mockFirebaseMessaging.channel to stub anything else.