Reputation: 95
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
class DataRepository {
final CollectionReference collection =
FirebaseFirestore.instance.collection('notes');
//Retour de models a la place de snapshots
Stream<QuerySnapshot> getStream() {
return collection.snapshots();
}
Stream<QuerySnapshot> getStreamDetail(String id) {
return collection.doc(id).collection('tasks').snapshots();
}
Stream<List<Note>> noteStream() {
final CollectionReference collection =
FirebaseFirestore.instance.collection('notes');
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.
new edit:
void main() {
test('should return data when the call to remote source is succesful.',
() async {
final FakeFirebaseFirestore fakeFirebaseFirestore = FakeFirebaseFirestore();
final DataRepository dataRepository = DataRepository();
final CollectionReference mockCollectionReference =
fakeFirebaseFirestore.collection(dataRepository.collection.path);
final List<Note> mockNoteList = <Note>[];
for (Note mockNote in mockNoteList) {
await mockCollectionReference.add(mockNote.toJson());
}
final Stream<List<Note>> noteStreamFromRepository =
dataRepository.noteStream();
final List<Note> actualNoteList = await noteStreamFromRepository.first;
final List<Note> expectedNoteList = mockNoteList;
expect(actualNoteList, expectedNoteList);
});
}
Upvotes: 4
Views: 4290
Reputation: 7726
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.
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);
});
The test above makes the following assumptions about your code:
FirebaseFirestore
object into the DataRepository
object.toSnapshot
method on your Note
object which converts your Note
object into a Map<String, dynamic>
object.The test works into the following way:
FakeFirebaseFirestore
object, the DataRepository
object, the mock CollectionReference
object and the mock data to be passed into the mock collection reference (mockNoteList
).DataRepository
's noteStream
method.DataRepository
is equal to the expected data i.e the data passed originally into the mock collection reference.For more understanding on unit testing Firestore in Flutter, check out the following resources:
fake_cloud_firestore
package in widget tests in Flutter.fake_cloud_firestore
package to test Firestore operations in Flutter Unit Tests, written by me.Add the FirebaseFirestore object as one of your constructor parameters and use that instead of FirebaseFirestore.instance
.
Update your DataRepository
to this below:
class DataRepository {
DataRepository({required this.firestore});
final FirebaseFirestore firestore;
CollectionReference get collection =>
firestore.collection('notes');
//Retour de models a la place de snapshots
Stream<QuerySnapshot> getStream() {
return collection.snapshots();
}
Stream<QuerySnapshot> getStreamDetail(String id) {
return collection.doc(id).collection('tasks').snapshots();
}
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;
}
}
Updated DataRepository Usage:
final FakeFirebaseFirestore fakeFirebaseFirestore = FakeFirebaseFirestore();
final DataRepository dataRepository =
DataRepository(firestore: fakeFirebaseFirestore);
final FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
final DataRepository dataRepository =
DataRepository(firestore: firebaseFirestore);
Upvotes: 11
Reputation: 1067
This should solve your problem: Specify a type for CollectionReference. This way:
class MockCollectionReference extends Mock implements CollectionReference<Map<String, dynamic>> {}
Upvotes: 1