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> 对象。

测试工作方式如下:

  1. 它创建测试所需的必要对象,即 FakeFirebaseFirestore 对象、DataRepository 对象、模拟 CollectionReference 对象和要传递到模拟集合中的模拟数据参考 (mockNoteList).
  2. 它将数据添加到模拟集合引用中。
  3. 它使用 DataRepositorynoteStream 方法获取数据。
  4. 它断言来自 DataRepository 的实际数据等于预期数据,即最初传递到模拟集合引用中的数据。

资源:

要进一步了解 Flutter 中的 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);