Flutter 单元测试 Firestore
Flutter unit testing firestore
总的来说,我是单元测试的新手。我正在尝试从我的 DataRepository 测试简单的方法。
遵循此 link 但似乎已弃用: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;
}
}
到目前为止,这是我的测试文件的样子:
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);
});
}
第一次给我这个错误
The argument type 'MockCollectionReference' can't be assigned to the parameter type 'CollectionReference<Map<String, dynamic>>'
如果能帮助我测试该方法,我将不胜感激。
新编辑:
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);
});
}
这应该可以解决您的问题:
指定 CollectionReference 的类型。这样:
class MockCollectionReference extends Mock implements CollectionReference<Map<String, dynamic>> {}
您可以使用 fake_cloud_firestore 来模拟 Firestore 实例,方法是使用它的 FakeCloudFirestore
对象来代替实际的 FirebaseFirestore
对象。
一个例子:
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);
});
解释:
上面的测试对您的代码做出了以下假设:
- 您将
FirebaseFirestore
对象传递给 DataRepository
对象。
- 您的
Note
对象上有一个 toSnapshot
方法,可将您的 Note
对象转换为 Map<String, dynamic>
对象。
测试工作方式如下:
- 它创建测试所需的必要对象,即
FakeFirebaseFirestore
对象、DataRepository
对象、模拟 CollectionReference
对象和要传递到模拟集合中的模拟数据参考 (mockNoteList
).
- 它将数据添加到模拟集合引用中。
- 它使用
DataRepository
的 noteStream
方法获取数据。
- 它断言来自
DataRepository
的实际数据等于预期数据,即最初传递到模拟集合引用中的数据。
资源:
要进一步了解 Flutter 中的 Firestore 单元测试,请查看以下资源:
- FlutterFire's Documentation on Testing,概述如何在 Flutter 的小部件测试中使用
fake_cloud_firestore
包。
- Mocking and Testing Firestore Operations in Flutter Unit Tests | Part 1 (Documents and Collections),一篇关于在 Flutter 单元测试中使用
fake_cloud_firestore
包测试 Firestore 操作的文章,由我撰写。
更新
将 FirebaseFirestore 对象添加为您的构造函数参数之一,并使用它代替 FirebaseFirestore.instance
。
将您的 DataRepository
更新为以下内容:
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;
}
}
更新的 DataRepository 用法:
- 在测试中:
final FakeFirebaseFirestore fakeFirebaseFirestore = FakeFirebaseFirestore();
final DataRepository dataRepository =
DataRepository(firestore: fakeFirebaseFirestore);
- 在应用程序中:
final FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
final DataRepository dataRepository =
DataRepository(firestore: firebaseFirestore);
总的来说,我是单元测试的新手。我正在尝试从我的 DataRepository 测试简单的方法。
遵循此 link 但似乎已弃用: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;
}
}
到目前为止,这是我的测试文件的样子:
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);
});
}
第一次给我这个错误
The argument type 'MockCollectionReference' can't be assigned to the parameter type 'CollectionReference<Map<String, dynamic>>'
如果能帮助我测试该方法,我将不胜感激。
新编辑:
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);
});
}
这应该可以解决您的问题: 指定 CollectionReference 的类型。这样:
class MockCollectionReference extends Mock implements CollectionReference<Map<String, dynamic>> {}
您可以使用 fake_cloud_firestore 来模拟 Firestore 实例,方法是使用它的 FakeCloudFirestore
对象来代替实际的 FirebaseFirestore
对象。
一个例子:
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);
});
解释:
上面的测试对您的代码做出了以下假设:
- 您将
FirebaseFirestore
对象传递给DataRepository
对象。 - 您的
Note
对象上有一个toSnapshot
方法,可将您的Note
对象转换为Map<String, dynamic>
对象。
测试工作方式如下:
- 它创建测试所需的必要对象,即
FakeFirebaseFirestore
对象、DataRepository
对象、模拟CollectionReference
对象和要传递到模拟集合中的模拟数据参考 (mockNoteList
). - 它将数据添加到模拟集合引用中。
- 它使用
DataRepository
的noteStream
方法获取数据。 - 它断言来自
DataRepository
的实际数据等于预期数据,即最初传递到模拟集合引用中的数据。
资源:
要进一步了解 Flutter 中的 Firestore 单元测试,请查看以下资源:
- FlutterFire's Documentation on Testing,概述如何在 Flutter 的小部件测试中使用
fake_cloud_firestore
包。 - Mocking and Testing Firestore Operations in Flutter Unit Tests | Part 1 (Documents and Collections),一篇关于在 Flutter 单元测试中使用
fake_cloud_firestore
包测试 Firestore 操作的文章,由我撰写。
更新
将 FirebaseFirestore 对象添加为您的构造函数参数之一,并使用它代替 FirebaseFirestore.instance
。
将您的 DataRepository
更新为以下内容:
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;
}
}
更新的 DataRepository 用法:
- 在测试中:
final FakeFirebaseFirestore fakeFirebaseFirestore = FakeFirebaseFirestore();
final DataRepository dataRepository =
DataRepository(firestore: fakeFirebaseFirestore);
- 在应用程序中:
final FirebaseFirestore firebaseFirestore = FirebaseFirestore.instance;
final DataRepository dataRepository =
DataRepository(firestore: firebaseFirestore);