Skip to content
DeveloperMemos

Mocking Firebase Analytics for unit tests(Flutter)

Dart, Flutter, Issues1 min read

Recently I was upgrading Flutter and some outdated packages in one of my projects and I upgraded the firebase_analytics package, this caused some of my unit tests to break and I had to do a little bit of troubleshooting to figure out what the issue was.

In the end I'm not 100% sure what caused this but it looks like there were some changes made to the firebase_analytics package since the last time I updated. When my unit tests previously made calls to send Firebase events nothing would happen and the tests would pass without any issues. After making the upgrade trying to make any calls that would send events caused an error, saying I needed to initialize the library(but they still didn't work even if I did that). Here's the specific error I was getting:

1[core/no-app] No Firebase App '[DEFAULT]' has been created - call Firebase.initializeApp()

The most simple way to solve this is to just create a mock for your class using the mockito package. I wrote about this a little bit in a post last year, when I needed to mock navigation in a unit test. This time I didn't end up actually using any code generation though.

In this particular project I have a class called AnalyticsUtil, it's nothing special:

1import 'package:firebase_analytics/firebase_analytics.dart';
2import 'package:logger/logger.dart';
3
4class AnalyticsUtil {
5 final _logger = Logger();
6
7 void logEvent({
8 required String name,
9 Map<String, dynamic>? parameters,
10 }) {
11 _logger.d('Sending analytics event: $name');
12 if (parameters != null) {
13 FirebaseAnalytics.instance.logEvent(
14 name: name,
15 parameters: parameters,
16 );
17 } else {
18 FirebaseAnalytics.instance.logEvent(
19 name: name,
20 );
21 }
22 }
23}

I use this with riverpod in my project but I will gloss over that part because it isn't important. Calling logEvent on FirebaseAnalytics is what was causing the new issue. Anyway after installing mockito you can do something like this in your unit test:

1class _AnalyticsMock extends Mock implements AnalyticsUtil {
2 @override
3 void logEvent({required String name, Map<String, dynamic>? parameters}) {}
4}

Then when you need to test something using this class, or inject it into another class you just create an instance:

1final analytics = _AnalyticsMock();

And off you go! You won't have any issues anymore if you are calling logEvent somewhere in your view models etc.