-
-
Save utkarsh-UK/1a1d2c25fad9cbbc19df5c3a26655a82 to your computer and use it in GitHub Desktop.
import 'package:cloud_firestore/cloud_firestore.dart'; | |
class MockFirestore extends Mock implements FirebaseFirestore {} | |
class MockCollectionReference extends Mock implements CollectionReference {} | |
class MockDocumentReference extends Mock implements DocumentReference {} | |
class MockDocumentSnapshot extends Mock implements DocumentSnapshot {} | |
void main() { | |
MockFirestore instance; | |
MockDocumentSnapshot mockDocumentSnapshot; | |
MockCollectionReference mockCollectionReference; | |
MockDocumentReference mockDocumentReference; | |
setUp(() { | |
instance = MockFirestore(); | |
mockCollectionReference = MockCollectionReference(); | |
mockDocumentReference = MockDocumentReference(); | |
mockDocumentSnapshot = MockDocumentSnapshot(); | |
}); | |
//Get data from firestore doc | |
test('should return data when the call to remote source is successful.', () async { | |
when(instance.collection(any)).thenReturn(mockCollectionReference); | |
when(mockCollectionReference.doc(any)).thenReturn(mockDocumentReference); | |
when(mockDocumentReference.get()).thenAnswer((_) async => mockDocumentSnapshot); | |
when(mockDocumentSnapshot.data()).thenReturn(responseMap); | |
//act | |
final result = await remoteDataSource.getData('user_id'); | |
//assert | |
expect(result, userModel); //userModel is a object that is defined. Replace with you own model class object. | |
}); | |
//Add data to firestore doc | |
//This demonstrates chained call like (instance.collection('path1').doc('doc1').collection('path2').doc('doc2').add(data)); | |
//We return the same mocked objects for each call. | |
test('should get data from nested document.', () async { | |
// arrange | |
when(instance.collection(any)).thenReturn(mockCollectionReference); | |
when(mockCollectionReference.doc(any)).thenReturn(mockDocumentReference); | |
when(mockDocumentReference.collection(any)).thenReturn(mockCollectionReference); | |
when(mockCollectionReference.add(any)).thenAnswer((_) async => mockDocumentReference); | |
when(mockDocumentReference.id).thenReturn(messageID); | |
when(mockDocumentSnapshot.data()).thenReturn(messageData); | |
//act | |
final result = await remoteDataSource.addData(userID, notificationID); | |
//assert | |
expect(result, notificationID); | |
}); | |
//Get list of documents from firestore. | |
test('should get list of all the documents.', () async { | |
// arrange | |
when(instance.collection(any)).thenReturn(mockCollectionReference); | |
when(mockCollectionReference.doc(any)).thenReturn(mockDocumentReference); | |
when(mockDocumentReference.get()).thenAnswer((_) async => mockDocumentSnapshot); | |
when(mockDocumentSnapshot.data()).thenReturn(roomsMap); | |
when(mockDocumentReference.collection(any)).thenReturn(mockCollectionReference); | |
when(mockCollectionReference.get()).thenAnswer((_) async => mockQuerySnapshot); | |
when(mockQuerySnapshot.docs).thenReturn([mockQueryDocumentSnapshot]); | |
when(mockQueryDocumentSnapshot.data()).thenReturn(membersMap); | |
//act | |
final result = await remoteDataSource.fetchUsers(); | |
//assert | |
expect(result, users); | |
}); | |
//Delete doc in firestore. | |
test('should delete a doc and return true.', () async { | |
// arrange | |
when(instance.collection(any)).thenReturn(mockCollectionReference); | |
when(mockCollectionReference.doc(any)).thenReturn(mockDocumentReference); | |
when(mockDocumentReference.collection(any)).thenReturn(mockCollectionReference); | |
when(mockCollectionReference.doc(any)).thenReturn(mockDocumentReference); | |
when(mockDocumentReference.delete()).thenAnswer((_) async => Future.value()); | |
//act | |
final result = await remoteDataSource.joinSquad(); | |
//assert | |
expect(result, true); | |
}); | |
//Mock query methods like orderBy(), limit(). | |
test('should return previous messages when getting data is successful.', () async { | |
// arrange | |
when(instance.collection(any)).thenReturn(mockCollectionReference); | |
when(mockCollectionReference.doc(any)).thenReturn(mockDocumentReference); | |
when(mockDocumentReference.collection('messages')).thenReturn(mockCollectionReference); | |
when(mockCollectionReference.doc(lastMessageID)).thenReturn(mockDocumentReference); | |
when(mockDocumentReference.get()).thenAnswer((realInvocation) async => mockDocumentSnapshot); | |
when(mockCollectionReference.orderBy('timestamp', descending: true)).thenReturn(mockQuery); | |
when(mockQuery.startAfterDocument(mockDocumentSnapshot)).thenReturn(mockQuery); | |
when(mockQuery.limit(20)).thenReturn(mockQuery); | |
when(mockQuery.get()).thenAnswer((_) async => mockQuerySnapshot); | |
when(mockQuerySnapshot.docs).thenReturn([mockQueryDocumentSnapshot]); | |
when(mockQueryDocumentSnapshot.data()).thenReturn(message); | |
//act | |
final result = await remoteDataSource.loadPreviousMessages(roomID: roomID, lastFetchedMessageID: lastMessageID); | |
//assert | |
expect(result, messages); | |
}); | |
} |
Hi @utkarsh-UK! I read your medium article about Writing Unit Tests in Flutter with Firebase Firestore. I tried to mock the unit test as you suggested but I stumbled across some problems. Is it possible to see a complete example of your code? Or if that is not possible, could you explain what
responseMap
would be?Also did you have any issues mocking
FirebaseFirestore.instance
? I followed the instructions here, however I always receive the errorMissingPluginException(No implementation found for method DocumentReference#get on channel plugins.flutter.io/firebase_firestore)
.Thanks in advance!
Hi @jlaskowska, thanks for reading my article and kudos to your efforts.
- I can't share the full code as of now as I'm bounded legally. But as you asked, the
responseMap
is just aMap<String, dynamic>
map which you are expecting to be returned from fireabse. Here is an example of what I've used relative to my needs:
final responseMap = { "name": "name", "image": url"", "last_read": "", "id": "id" };
Hope this solves your problem!
- For your second query, it would be helpful to know if you're mocking Firestore instance for unit tests or widget tests? Please revert back on this with firestore lib version so that I can dig down to right direction.
Thanks!
Hi @utkarsh-UK! Thanks for your quick reply. I am mocking Firestore instance for unit tests. The version of firebase lib that I am using is firebase_core: ^0.5.1
.
I'll write here if I find the solution.
I have followed all the steps and even added a separate file mock.dart
(just copy pasted code from here https://github.com/FirebaseExtended/flutterfire/blob/master/packages/cloud_firestore/cloud_firestore/test/mock.dart) in order to fix problems with Firebase.initializeApp()
. I ended up getting the following errors:
MissingPluginException(No implementation found for method DocumentReference#get on channel plugins.flutter.io/firebase_firestore)
package:cloud_firestore_platform_interface/src/method_channel/utils/exception.dart 13:5 convertPlatformException
package:cloud_firestore_platform_interface/src/method_channel/method_channel_document_reference.dart 80:13 MethodChannelDocumentReference.get
Hey, I finally pass the firestore unit test. But again I am stuck in a point where I need to test a function called writeNewUser that returns a void by creating a new document when it called. I tried to test that as follows using verify()
verify(instance.collection(''Name"))
verify(mockCollectionReference.doc(''Name''))
but only the first verify method gets call but the writeNewUser() function executes without any error perfectly as I expected.
You may update this for null-safety.
Right now, I get
type 'MockCollectionReference<Object?>' is not a subtype of type 'MockCollectionReference<Map<String, dynamic>>' in type cast
on when(firestore.collection("users")).thenReturn(userCollection);
I figured it out how to use your implementation In null-safety and with the code generation of Mockito.
Code gen:
Map<String, bool> getData() {
return {}; //this will be overriden
}
@GenerateMocks(
[
FirebaseFirestore,
CollectionReference,
DocumentReference,
QuerySnapshot,
],
customMocks: [
MockSpec<QueryDocumentSnapshot>(
as: #MockQueryDocumentSnapshot, fallbackGenerators: {#data: getData}),
],
)
Then in your declaration of your mocked vars you need to tell the compiler what you are actually extending:
late MockFirebaseFirestore firestore;
late MockCollectionReference<Map<String, dynamic>> userCollection;
late MockDocumentReference<Map<String, dynamic>> doc;
late MockCollectionReference<Map<String, dynamic>> notificationCollection;
late MockQuerySnapshot<Map<String, dynamic>> querySnapshot;
late MockQueryDocumentSnapshot<Map<String, dynamic>> queryDocumentSnapshot;
...
setState
...
Here is a usage of my mocked methods:
when(firestore.collection("users")).thenReturn(userCollection);
when(userCollection.doc("1")).thenReturn(doc);
when(doc.collection("notifications")).thenReturn(notificationCollection);
when(notificationCollection.get()).thenAnswer((_) async => querySnapshot);
when(querySnapshot.docs)
.thenAnswer((realInvocation) => [queryDocumentSnapshot]);
when(queryDocumentSnapshot.data())
.thenAnswer((realInvocation) => {"message": true});
To understand why the custom mock is needed read this issue and the readme of the Mockito repo.
Hope that helps anyone.
when(instance.collection("sold")).thenReturn(mockCollectionReferenceSold);
when(mockCollectionReferenceSold.doc("abc"))
.thenReturn(mockDocumentReferenceSold);
when(mockDocumentReferenceSold.set({
'appointmentID': "tAppointmentID",
'date': DateTime.parse("2020-12-05 20:18:04Z"),
'description': "test description",
})).thenAnswer((_) async => mockDocumentSnapshotSold);
print(mockDocumentSnapshotSold.id);
prints null
any idea?
why data hasnt inserted into firestore?
If what You write is your whole code, then you are refering to mockDocumentSnapshotSold.id
, but didn't call mockDocumentReferenceSold
@Babwenbiber could u show in code how and where it shoudl be called? i am not getting you.
I am also stuck in the same as @sath26.
prints null
sath26 commented on Sep 16 •
when(instance.collection("sold")).thenReturn(mockCollectionReferenceSold);
when(mockCollectionReferenceSold.doc("abc"))
.thenReturn(mockDocumentReferenceSold);
when(mockDocumentReferenceSold.set({
'appointmentID': "tAppointmentID",
'date': DateTime.parse("2020-12-05 20:18:04Z"),
'description': "test description",
})).thenAnswer((_) async => mockDocumentSnapshotSold);
print(mockDocumentSnapshotSold.id);
prints null
any idea?
why data hasnt inserted into firestore?
How can we test streams in firestore and model class.
//arrange
when(instance.collection("todos")).thenReturn(mockCollectionReference);
when(mockCollectionReference.doc(any)).thenReturn(mockDocumentReference);
when(mockDocumentReference.collection("todos"))
.thenReturn(mockCollectionReference);
when(mockCollectionReference.snapshots())
.thenReturn(mockQuerySnapshotStream);
when(await mockQuerySnapshotStream.toList())
.thenReturn(mockQuerySnapshotList);
when(mockQuerySnapshotList.map((e) {
final List retVal = [];
for (final DocumentSnapshot doc in e.docs) {
retVal.add(TodoModel.fromDocumentSnapshot(documentSnapshot: doc));
}
return retVal;
}));
//test
int i = 0;
stream.listen(
expectAsync1((event) {
expect(event.content, actual[i].content);
i++;
}, count: take),
);
Hi @utkarsh-UK! I read your medium article about Writing Unit Tests in Flutter with Firebase Firestore. I tried to mock the unit test as you suggested but I stumbled across some problems. Is it possible to see a complete example of your code? Or if that is not possible, could you explain what
responseMap
would be?Also did you have any issues mocking
FirebaseFirestore.instance
? I followed the instructions here, however I always receive the errorMissingPluginException(No implementation found for method DocumentReference#get on channel plugins.flutter.io/firebase_firestore)
.Thanks in advance!