I'm encountering a type mismatch error when trying to use Mockito with Firestore mocks in my Flutter tests. Specifically, I'm getting the following error:
The argument type 'MockCollectionReference<Object?>' can't be assigned to the parameter type 'CollectionReference<Map<String, dynamic>>'.
I have a Flutter project using Firestore for data storage. I'm trying to mock Firestore and its related classes (CollectionReference, DocumentReference) using Mockito for unit testing. When setting up the mock interactions (when(...).thenReturn(...)), I'm encountering type mismatch errors related to generics. Setup Details:
I've generated mocks using @GenerateMocks for FirebaseFirestore, CollectionReference, DocumentReference, and other relevant classes. In my test setup (setUp method), I'm using these mocks to stub Firestore method calls (collection, doc).
Setup Details:
I've generated mocks using @GenerateMocks for FirebaseFirestore, CollectionReference, DocumentReference, and other relevant classes. In my test setup (setUp method), I'm using these mocks to stub Firestore method calls (collection, doc).
Code:
@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));
});
});
}
mockCollectionReference
is of type MockCollectionReference
, which, since it's a generic, is shorthand for MockCollectionReference<Object?>
.
Generic<BaseClass>
is not substitutable for Generic<DerivedClass>
, so MockCollectionReference<Object?>
(which we can consider to be a CollectionReference<Object?>
) is not substitutable for a CollectionReference<Map<String, dynamic>>
.
You instead should explicitly declare mockCollectionReference
as a MockCollectionReference<Map<String, dynamic>>
:
late MockCollectionReference<Map<String, dynamic>> mockCollectionReference;