Search code examples
flutterfirebasedartmockitobloc

Mockito BlocTest "type 'Null' is not a subtype of type 'Future<UserModel>'"


I am mocking my sign up function which utilizes firebase. My issue is that when I call the builder in the BlocTest, somehow it is getting null as the value. I don't understand, as kMockTeacher is defined as a UserModel in my user_model.dart:

final kMockTeacher = UserModel(
    firstName: 'Logan',
    lastName: 'V',
    email: '[email protected]',
    role: UserRole.teacher,
    token: '',
    id: '1');

build: () in auth_test.dart

 when(
          authService.signUpWithEmailAndPassword(registrationModel),
        ).thenReturn(
          Future<UserModel>.value(kMockTeacher),
        );

services.dart

Future<UserModel> signUpWithEmailAndPassword(
    final UserRegistrationModel user,
  );

auth_test.dart:

import 'package:bloc_test/bloc_test.dart';
import 'package:edtech/backend/services/services.dart';
import 'package:edtech/blocs/auth_cubit/auth_bloc.dart';
import 'package:edtech/models/models.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';

class MockedDatabaseService extends Mock implements DatabaseService {}

class MockedAuthService extends Mock implements AuthService {}

void main() {
  group("Test Sign Up functions", () {
    late AuthService authService;
    late DatabaseService databaseService;
    late AuthBloc bloc;
    late UserRegistrationModel registrationModel;

    setUpAll(() {
      authService = MockedAuthService();
      databaseService = MockedDatabaseService();
      registrationModel = UserRegistrationModel(
          password: 'password',
          firstName: kMockTeacher.firstName,
          lastName: kMockTeacher.lastName,
          email: kMockTeacher.email,
          role: kMockTeacher.role);
      bloc = AuthBloc(UnAuthenticatedState(), authService);
    });

    blocTest<AuthBloc, AuthState>(
      'emits AuthLoading followed by AuthenticatedState',

      build: () {
        when(
          authService.signUpWithEmailAndPassword(registrationModel),
        ).thenReturn(
          Future<UserModel>.value(kMockTeacher),
        );

        return bloc;
      },
      act: (bloc) => bloc.signUp(user: registrationModel),
      expect: () => [
        AuthLoadingState(),
        AuthenticatedState(user: kMockTeacher),
      ],
    );

    tearDown(() {
      bloc.close();
    });
  });
}

I have ran the test in debug mode attempting to get the value of Future<UserModel>.value(kMockTeacher), but compilation fails before I can get it.


Solution

  • Using thenReturn to return a Future or Stream will throw an ArgumentError.

    Since your authService.signUpWithEmailAndPassword(registrationModel) returns a Future, you have to use thenAnswer.

    when(
      authService.signUpWithEmailAndPassword(registrationModel),
    ).thenAnswer((_) => Future<UserModel>.value(kMockTeacher));
    

    See a quick word on async stubbing for more information.