I'm new to unit testing in general. I'm trying to test simple method from my DataRepository.
Following this link but seems deprecated: https://utkarshkore.medium.com/writing-unit-tests-in-flutter-with-firebase-firestore-72f99be85737
Stream<List<Note>> noteStream() {
try {
return collection.snapshots().map((notes) {
final List<Note> notesFromFirestore = <Note>[];
for (var doc in notes.docs) {
notesFromFirestore.add(Note.fromSnapshot(doc));
}
return notesFromFirestore;
});
} catch (e) {
rethrow;
}
}
So far this is what my test file look like:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
class MockFirestore extends Mock implements FirebaseFirestore {}
class MockCollectionReference extends Mock implements CollectionReference {}
void main() {
MockFirestore instance = MockFirestore();
MockCollectionReference mockCollectionReference = MockCollectionReference();
test('should return data when the call to remote source is succesful.',
() async {
when(instance.collection('notes')).thenReturn(mockCollectionReference);
});
}
First instance throw me this error
The argument type 'MockCollectionReference' can't be assigned to the parameter type 'CollectionReference<Map<String, dynamic>>'
I would really appreciate the help for testing the method.
CodePudding user response:
This should solve your problem: Specify a type for CollectionReference. This way:
class MockCollectionReference extends Mock implements CollectionReference<Map<String, dynamic>> {}
CodePudding user response:
You can use the fake_cloud_firestore to mock the Firestore instance by using it's FakeCloudFirestore object that can be used in the place of an actual FirebaseFirestore object.
An Example:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:fake_cloud_firestore/fake_cloud_firestore.dart';
test('noteStream returns Stream containing List of Note objects', () async {
//Define parameters and objects
final FakeFirebaseFirestore fakeFirebaseFirestore = FakeFirebaseFirestore();
final DataRepository dataRepository =
DataRepository(firestore: fakeFirebaseFirestore);
final CollectionReference mockCollectionReference =
fakeFirebaseFirestore.collection(dataRepository.collection.path);
final List<Note> mockNoteList = [Note()];
// Add data to mock Firestore collection
for (Note mockNote in mockNoteList) {
await mockCollectionReference.add(mockNote.toSnapshot());
}
// Get data from DataRepository's noteStream i.e the method being tested
final Stream<List<Note>> noteStreamFromRepository =
dataRepository.noteStream();
final List<Note> actualNoteList = await noteStreamFromRepository.first;
final List<Note> expectedNoteList = mockNoteList;
// Assert that the actual data matches the expected data
expect(actualNoteList, expectedNoteList);
});
Explanation:
The test above makes the following assumptions about your code:
- You pass the
FirebaseFirestoreobject into theDataRepositoryobject. - You have a
toSnapshotmethod on yourNoteobject which converts yourNoteobject into aMap<String, dynamic>object.
The test works into the following way:
- It creates the necessary objects needed for the test i.e the
FakeFirebaseFirestoreobject, theDataRepositoryobject, the mockCollectionReferenceobject and the mock data to be passed into the mock collection reference (mockNoteList). - It adds the data into the mock collection reference.
- It gets the data using the
DataRepository'snoteStreammethod. - It asserts that the actual data from the
DataRepositoryis equal to the expected data i.e the data passed originally into the mock collection reference.
Resources:
For more understanding on unit testing Firestore in Flutter, check out the following resources:
- FlutterFire's Documentation on Testing, an overview on how to use the
fake_cloud_firestorepackage in widget tests in Flutter. - Mocking and Testing Firestore Operations in Flutter Unit Tests | Part 1 (Documents and Collections), an article about using the
fake_cloud_firestorepackage to test Firestore operations in Flutter Unit Tests, written by me.
