代码之家  ›  专栏  ›  技术社区  ›  Corner

在Flutter测试中将Mockito与Firestore模型一起使用时出现类型不匹配错误

  •  0
  • Corner  · 技术社区  · 1 年前

    当我在Flutter测试中尝试将Mockito与Firestore mocks一起使用时,遇到了一个类型不匹配的错误。具体来说,我得到了以下错误:

    The argument type 'MockCollectionReference<Object?>' can't be assigned to the parameter type 'CollectionReference<Map<String, dynamic>>'.
    

    我有一个使用Firestore进行数据存储的Flutter项目。 我正在尝试使用Mockito模拟Firestore及其相关类(CollectionReference、DocumentReference)进行单元测试。 在设置模拟交互时(When(…).thenReturn(…)),我遇到了与泛型相关的类型不匹配错误。 设置详细信息:

    我已经使用@GenerateMocks为FirebaseFirestore、CollectionReference、DocumentReference和其他相关类生成了mock。 在我的测试设置(setup方法)中,我使用这些mock来存根Firestore方法调用(collection,doc)。

    设置详细信息:

    我已经使用@GenerateMocks为FirebaseFirestore、CollectionReference、DocumentReference和其他相关类生成了mock。 在我的测试设置(setup方法)中,我使用这些mock来存根Firestore方法调用(collection,doc)。

    密码

    @GenerateMocks([
    FirebaseAuth,
    FirebaseStorage,
    FirebaseMessaging,
    FirebaseFirestore,
    CollectionReference,
    DocumentReference,
    CheckPhoneAuthUserUseCase,
    CheckAnonymousUserUsecase,
    GetCurrentUidUseCase,
    WriteCurrentTaskToLogUseCase,
    ])
    
    void main() {
      TestWidgetsFlutterBinding.ensureInitialized();
      setupFirebaseCoreMocks(); // Mocks initialization for Firebase
    
      late AdministrationRemoteDataSourceRepositoryImpl repository;
      late MockCheckPhoneAuthUserUseCase mockCheckPhoneAuthUserUseCase;
      late MockCheckAnonymousUserUsecase mockCheckAnonymousUserUseCase;
      late MockGetCurrentUidUseCase mockGetCurrentUidUseCase;
      late MockWriteCurrentTaskToLogUseCase mockWriteCurrentTaskToLogUseCase;
      late MockFirebaseFirestore mockFirebaseFirestore;
      late MockCollectionReference mockCollectionReference;
      late MockDocumentReference mockDocumentReference;
      late MockFirebaseMessaging mockFirebaseMessaging;
      late MockFirebaseStorage mockFirebaseStorage;
      late MockFirebaseAuth mockFirebaseAuth;
    
      setUpAll(() async {
        await Firebase.initializeApp(); // Initialize Firebase app
      });
    
      setUp(() {
        mockCheckPhoneAuthUserUseCase = MockCheckPhoneAuthUserUseCase();
        mockCheckAnonymousUserUseCase = MockCheckAnonymousUserUsecase();
        mockGetCurrentUidUseCase = MockGetCurrentUidUseCase();
        mockWriteCurrentTaskToLogUseCase = MockWriteCurrentTaskToLogUseCase();
        mockFirebaseFirestore = MockFirebaseFirestore();
        mockCollectionReference = MockCollectionReference();
        mockDocumentReference = MockDocumentReference();
        mockFirebaseAuth = MockFirebaseAuth();
        mockFirebaseStorage = MockFirebaseStorage();
        mockFirebaseMessaging = MockFirebaseMessaging();
    
        repository = AdministrationRemoteDataSourceRepositoryImpl(
          firebaseFirestore: mockFirebaseFirestore,
          firebaseMessaging: mockFirebaseMessaging,
          firebaseAuth: mockFirebaseAuth,
          firebaseStorage: mockFirebaseStorage,
          remoteService: null,
        );
    
        when(mockFirebaseFirestore.collection(any))
            .thenReturn(mockCollectionReference);
        when(mockCollectionReference.doc(any))
            .thenReturn(mockDocumentReference);
      });
    
      group('verifyStore', () {
        const storeId = 'testStoreId';
        const currentState = false;
        const uid = 'testUid';
    
        test('should return Success when all checks pass and store is verified',
            () async {
          // Arrange
          when(mockCheckPhoneAuthUserUseCase.call()).thenAnswer((_) async => true);
          when(mockCheckAnonymousUserUseCase.call()).thenAnswer((_) async => false);
          when(mockGetCurrentUidUseCase.call()).thenAnswer((_) async => uid);
          when(mockDocumentReference.update(any))
              .thenAnswer((_) async => Right(Success(message: "Done")));
          when(mockWriteCurrentTaskToLogUseCase.call(any))
              .thenAnswer((_) async => null);
    
          // Act
          final result = await repository.verifyStore(storeId, currentState);
    
          // Assert
          expect(result, Right(Success(message: "Successfully updated")));
          verify(mockCheckPhoneAuthUserUseCase.call());
          verify(mockCheckAnonymousUserUseCase.call());
          verify(mockGetCurrentUidUseCase.call());
          verify(mockDocumentReference.update(any));
          verify(mockWriteCurrentTaskToLogUseCase.call(any));
        });
    
        test('should return Failure when user is not authenticated with phone number',
            () async {
          // Arrange
          when(mockCheckPhoneAuthUserUseCase.call()).thenAnswer((_) async => false);
    
          // Act
          final result = await repository.verifyStore(storeId, currentState);
    
          // Assert
          expect(result, Left(Failure(message: "Invalid access")));
          verify(mockCheckPhoneAuthUserUseCase.call());
          verifyNever(mockCheckAnonymousUserUseCase.call());
          verifyNever(mockGetCurrentUidUseCase.call());
          verifyNever(mockDocumentReference.update(any));
        });
    
        test('should return Failure when user is anonymous', () async {
          // Arrange
          when(mockCheckPhoneAuthUserUseCase.call()).thenAnswer((_) async => true);
          when(mockCheckAnonymousUserUseCase.call()).thenAnswer((_) async => true);
    
          // Act
          final result = await repository.verifyStore(storeId, currentState);
    
          // Assert
          expect(result, Left(Failure(message: "Invalid access")));
          verify(mockCheckPhoneAuthUserUseCase.call());
          verify(mockCheckAnonymousUserUseCase.call());
          verifyNever(mockGetCurrentUidUseCase.call());
          verifyNever(mockDocumentReference.update(any));
        });
    
        test('should return Failure when there is a SocketException', () async {
          // Arrange
          when(mockCheckPhoneAuthUserUseCase.call()).thenAnswer((_) async => true);
          when(mockCheckAnonymousUserUseCase.call()).thenAnswer((_) async => false);
          when(mockGetCurrentUidUseCase.call()).thenAnswer((_) async => uid);
          when(mockDocumentReference.update(any)).thenThrow(SocketException('No Internet'));
    
          // Act
          final result = await repository.verifyStore(storeId, currentState);
    
          // Assert
          expect(result, Left(Failure(message: 'No Internet')));
          verify(mockCheckPhoneAuthUserUseCase.call());
          verify(mockCheckAnonymousUserUseCase.call());
          verify(mockGetCurrentUidUseCase.call());
          verifyNever(mockDocumentReference.update(any));
        });
    
        test('should return Failure when there is an unexpected exception', () async {
          // Arrange
          when(mockCheckPhoneAuthUserUseCase.call()).thenAnswer((_) async => true);
          when(mockCheckAnonymousUserUseCase.call()).thenAnswer((_) async => false);
          when(mockGetCurrentUidUseCase.call()).thenAnswer((_) async => uid);
          when(mockDocumentReference.update(any)).thenThrow(Exception('Unexpected error'));
    
          // Act
          final result = await repository.verifyStore(storeId, currentState);
    
          // Assert
          expect(result, Left(Failure(message: 'Exception: Unexpected error')));
          verify(mockCheckPhoneAuthUserUseCase.call());
          verify(mockCheckAnonymousUserUseCase.call());
          verify(mockGetCurrentUidUseCase.call());
          verifyNever(mockDocumentReference.update(any));
        });
      });
    }
    
    1 回复  |  直到 1 年前
        1
  •  1
  •   jamesdlin    1 年前

    mockCollectionReference 属于类型 MockCollectionReference ,由于它是泛型,因此是 MockCollectionReference<Object?> .

    Generic<BaseClass> 不能替代 Generic<DerivedClass> 所以 实物收藏参考<对象gt; (我们可以认为是 CollectionReference<Object?> )不能替代 CollectionReference<Map<String, dynamic>> .

    相反,您应该显式声明 mockCollectionReference 作为一个 MockCollectionReference<Map<String, dynamic>> :

      late MockCollectionReference<Map<String, dynamic>> mockCollectionReference;