Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The mystery of Unit Testing with Firestore #17

Open
chstrong opened this issue Oct 10, 2020 · 2 comments
Open

The mystery of Unit Testing with Firestore #17

chstrong opened this issue Oct 10, 2020 · 2 comments

Comments

@chstrong
Copy link

chstrong commented Oct 10, 2020

Dear Resocoder,

Your tutorial is absolutely fantastic.

However, one mystery remains, and this is unit testing the NoteRepository class and the NoteWatcherBloc, and NoteActorBloc class with Firestore.

This is therefore a "feature" request.

Your tutorial is great but can get very complex for amateur programmers. So I'm trying a test-driven approach for your domain driven tutorial, in order to solve each concern separately. I'm starting therefore with the domain and infrastructure / repository layer.

Mockito doesn't seem to be able to accept constructors and hence I can't pass a Mock instance of Firebase to the repository, or the Bloc. At the moment I'm thinking of writing an additional method in the NoteRepository which I can use to parse the Firebase Mock instance, but I'm sure you will scream at me and tell me it's not good code practice :) And the problem with the Bloc still remains.

I think a separate video would be helpful that explains how to test repository and bloc classes with Firestore.

There is nobody, that is showing this, so it seems to be a complex topic that nobody can copy, as there are no examples :).

Or all use AWS Lambda with JSON and nobody uses Firebase :)

All are showing FirebaseAuth, but nobody shows how to test repository classes and blocs. I didn't figure out how to do it yet but am working on it.

@manuelvargastapia
Copy link

Hi @chstrong. I also struggled a lot with testing Firestore and finally, I used the cloud_firestore_mocks package. It's still tricky but did the trick. You can check my code for examples.

To test a bloc, primary you'll need the bloc_test package. With it, it's pretty easy to implement unit testing in blocs. Again, you could check my code for examples.

@manjavacasjaime
Copy link

manjavacasjaime commented Nov 28, 2021

THIS WORKS FOR ME.
I've followed ResoCoder's tutorial step by step.

I was having a lot of trouble trying to test widgets that use BloCs, whose repositories communicate with Firebase.
Hope this makes things easier.

1. These are my imports and the annotations used to auto-generate the mocks for my IBlaBlaRepository:
Note: casedashboard_widget_test.mocks.dart is an auto-generated file. In order to generate yours, add mockito's GenerateMocks annotation and run "flutter pub run build_runner build --delete-conflicting-outputs".

import 'package:bethemis_abogados/application/chat/message_watcher/message_watcher_bloc.dart';
import 'package:bethemis_abogados/application/expense/expense_watcher_bloc.dart';
import 'package:bethemis_abogados/domain/chat/i_message_repository.dart';
import 'package:bethemis_abogados/domain/expense/i_expense_repository.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';

import 'casedashboard_widget_test.mocks.dart';

@GenerateMocks([
IExpenseRepository
], customMocks: [
MockSpec<,IMessageRepository>(returnNullOnMissingStub: true),
])
void main() {

2. This is the "stream" variable that I want to be returned by one of my Repository methods.
Instead of calling Firebase, the Repository method will return this variable.

var messageAux = Message(
messageID: UniqueId(),
date: DateTime.utc(1989, 11, 9),
from: UniqueId(),
text: 'text',
);
var list = listOf(messageAux);
final stream = Stream<Either<MessageFailure, KtList<,Message>>>.fromIterable([right(list)]);

3. And, finally, here's a look at the testWidgets method.
Note: the BloCs are not being mocked. I'm just creating them with the IBlaBlaRepository auto-generated mocks.
Note: I use mockito's when( ) method to return the "stream" that I've mentioned before.
Note: make sure that the BlocProviders you're using are outside the widget you're testing.

testWidgets(
'Dashboard shows desired reduxWidgets when the selected case is not null',
(WidgetTester tester) async {

  IMessageRepository messageRepository = MockIMessageRepository();
  when(messageRepository.watchAllMessages(caseAux, 20)).thenAnswer((_) => stream);

  MessageWatcherBloc messageWatcherBloc = MessageWatcherBloc(messageRepository);
  IExpenseRepository expenseRepository = MockIExpenseRepository();
  ExpenseWatcherBloc expenseWatcherBloc = ExpenseWatcherBloc(expenseRepository);

  var widget = MaterialApp(
    home: MultiBlocProvider(
      providers: [
        BlocProvider<MessageWatcherBloc>.value(value: messageWatcherBloc),
        BlocProvider<ExpenseWatcherBloc>.value(value: expenseWatcherBloc),
      ],
      child: CaseDashboard(myCase: caseAux),
    ),
  );

  await tester.pumpWidget(widget);

  final seleccioneTextFinder = find.text(seleccioneUnCasoText);
  final reduxWidgetFinder = find.byKey(const Key('reduxWidget'));

  expect(seleccioneTextFinder, findsNothing);
  expect(reduxWidgetFinder, findsNWidgets(5));
},

);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants