ssiddh
ssiddh

Reputation: 520

How to unit test methods using Firebase Cloud Firestore?

I am trying to use Cloud Firestore on Flutter. So far I have been able to use it but I want to include unit tests for the functions which use firestore, in my project. I am making use of Mockito to do the same and I think it should work.

But I am really stumped at StreamMatchers of Dart. I am not able to wrap my head around the error message.

Below is some code of what I am trying to achieve and the error I am getting.

repository.dart

    import 'dart:async';

    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:sunapsis_conference18/models/conference_event.dart';

    Stream<List<ConferenceEvent>> getAllEvents() {
        return _firestore
            .collection(_collectionName)
            .snapshots()
            .map((QuerySnapshot snapshot) => _eventMapper(snapshot));
    }
  

    List<ConferenceEvent> _eventMapper(QuerySnapshot snapshot) {
        List<ConferenceEvent> events = [];
        for (int i = 0; i < snapshot.documents.length; i++) {
          DocumentSnapshot documentSnapshot = snapshot.documents[i];
          ConferenceEvent event =
              ConferenceEvent.buildFromMap(documentSnapshot.data);
          events.add(event);
        }
        return events;
    }

It method tries to get data from a firestore collection and return a stream of list of data objects.

repository_test.dart

    import 'dart:async';

    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:mockito/mockito.dart';
    import 'package:sunapsis_conference18/models/conference_event.dart';
    import 'package:sunapsis_conference18/repository/repository.dart'; //quotation mark fix    
    import 'package:test/test.dart';

    class MockDocumentReference extends Mock implements DocumentReference {}
    
    class MockFirestore extends Mock implements Firestore {}
    
    class MockCollectionReference extends Mock implements CollectionReference {}
    
    class MockQuerySnapshot extends Mock implements QuerySnapshot {}
    
    class MockDocumentSnapshot extends Mock implements DocumentSnapshot {}
    
    class MockQuery extends Mock implements Query {}
    
    main() {
      group('getAllEvents() tests', () {
        final Firestore mockFirestore = MockFirestore();
        final CollectionReference mockCollectionReference =
            MockCollectionReference();
        final QuerySnapshot mockQuerySnapshot = MockQuerySnapshot();
        final DocumentSnapshot mockDocumentSnapshot = MockDocumentSnapshot();
        final Repository repository = Repository(mockFirestore);
        final DocumentReference _mockDocumentRef = MockDocumentReference();
        final Map<String, dynamic> _responseMap = {
          'foo': 123,
          'bar': 'Test title',
        };
        final ConferenceEvent _event = ConferenceEvent.buildFromMap(_responseMap);
    
        test('returns correct stream of list of ConferenceEvent', () async {
          when(mockFirestore.collection('events'))
              .thenReturn(mockCollectionReference);
          when(mockCollectionReference.snapshots())
              .thenAnswer((_) => Stream.fromIterable([mockQuerySnapshot]));
    
          when(mockQuerySnapshot.documents).thenReturn([mockDocumentSnapshot]);
          when(mockDocumentSnapshot.data).thenReturn(_responseMap);
          await expectLater(
              repository.getAllEvents(),
              emitsAnyOf([
                [_event],
                emitsDone
              ]));
        });
      });
    }

I am not able to formulate the right stream matcher and at the same time not able to comprehend the error message.

error

Expected: should do one of the following:
          • emit an event that [Instance of 'ConferenceEvent']
          • be done
  Actual: <Instance of '_MapStream<QuerySnapshot, List<ConferenceEvent>>'>
   Which: emitted • [Instance of 'ConferenceEvent']
                  x Stream closed.
            which failed all options:
                  • failed to emit an event that [Instance of 'ConferenceEvent'] because it emitted an event that was <Instance of 'ConferenceEvent'> instead of <Instance of 'ConferenceEvent'> at location [0]
                  • failed to be done

Any guidance to help understand the error message will be really appreciated. Also, is this the right approach to test this function?

Upvotes: 4

Views: 5308

Answers (1)

drosenberger
drosenberger

Reputation: 31

I think the problem is related to the way expectLater is comparing the instances of ConferenceEvent. It is using the == (equal) operator to compare those two objects and without overwriting the equal operator of in your ConferenceEvent those objects won't have the same hashCode.

In you mocked code there is a new object instantiated here

ConferenceEvent event =
          ConferenceEvent.buildFromMap(documentSnapshot.data);

And later you compare it with another object of ConferenceEvent created in this line:

final ConferenceEvent _event = ConferenceEvent.buildFromMap(_responseMap);

Upvotes: 1

Related Questions