Writing Unit Tests in Flutter with Firebase Firestore

In this article, we’ll see how to unit test your precious code with firestore without using any external library for mocking firestore.

UtkarshKore
3 min readNov 19, 2020

Before we begin

  • This article doesn’t use any libraries for firestore mocks. We’ll mock it manually to understand how Mockito works.
  • This article presumes that you’ve a beginner level understanding of Unit Tests in Flutter.
  • You must know firestore and it’s usage with Flutter.

Enough. Let’s,

Photo by Dayne Topkin on Unsplash

We will be creating mock classes for each of the firestore class. Remember, this article is to demonstrate how to create and use mocks in tests. If this seems very lengthy, you can always use predefined libraries for mocking. Let’s begin by adding dependencies for firestore and mockito packages. I’m assuming you’ve done that already.

Let’s create a mock class for Firestore instance like this.

class MockFirestore extends Mock implements FirebaseFirestore {}void main() {
MockFirestore instance;
setUp(() {
instance = MockFirestore();
});
}

Get Data from Firestore

Initialize the instance in setUp method. Let’s define a test that will get data from firestore document. I like to follow Arrange-Act-Assert paradigm in tests. So, under setUp method,

test('should return data when the call to remote source is successful.', () async {
// arrange

//act

//assert

});

And my actual method that performs fetching data is as follows,

Future<UserModel> getData(String userID) async {
Map<String, dynamic> data =
(await firestore.collection('users').doc(userID).get()).data();
return UserModel.fromJSON(data);
}

If you’ve already tried mocking firestore for this case as a beginner, you might have done something like this,

when(instance.collection('users').doc(senderID).get()).thenAnswer((_) => null);

But you faced an error that ‘doc’ was called on null. That’s because firestore.collection(path) returns a CollectionReference type which Mockito doesn’t understand. So, we’ve to tell mockito how to mock that in tests. For that,

class MockCollectionReference extends Mock implements CollectionReference {}class MockDocumentReference extends Mock implements DocumentReference {}class MockDocumentSnapshot extends Mock implements DocumentSnapshot {}

Initialize these as we did for Firestore instance. This is how it should look now.

Now we’ll do the actual magic. In arrange part, we’ll instruct mockito what to return when specific method of Firestore is called.

when(instance.collection(any)).thenReturn(mockCollectionReference);
when(mockCollectionReference.doc(any)).thenReturn(mockDocumentReference);
when(mockDocumentReference.get()).thenAnswer((_) async => mockDocumentSnapshot);
when(mockDocumentSnapshot.data()).thenReturn(responseMap);
  1. Start by returning CollectionReference for collection() method call.
  2. Then when doc() method is called on any CollectionReference, we’ll return mocked DocumentReference object.
  3. When we encounter a get() method we’ll simply answer a future with mocked DocumentSnapshot which actually contains our data. Notice, here we’ve used thenAnswer() because doc.get() returns a Future<DocumentSnapshot>.
  4. Finally, return the desired Map<String, dynamic> when we encounter any call for data().

This is how your final code should look like.

Full code after completing test

That’s it. You’ve to repeat these steps for other methods also. You can mock Query, Firestore Snapshots or even any other Firebase libraries like Storage, Auth with this approach. You can see the full example with other mocks here

As simple it is, the downside of this method is lot of boiler plate code and you may end up in copy pasting lot of lines. But for a start and to understand how mocking works, I’d really recommend this approach. Once you get hands of it, you can move to using external libraries.

Hope you learned something with this article. See you in next article.

Happy coding😉

--

--