dart-lang / mockito

Mockito-inspired mock library for Dart
https://pub.dev/packages/mockito
Apache License 2.0
633 stars 162 forks source link

How to mock third party lib dio's CancelToken?? #510

Closed CharanjeetRPOPS closed 2 years ago

CharanjeetRPOPS commented 2 years ago

i am using dio for making api request. ( https://pub.dev/packages/dio )

mockito: 5.0.17 , dio: 4.0.4

using clean architecture i want to pass CancelToken in different classes from bloc class. I tried to mock CancelToken with @GenerateMocks([CancelToken]) but i get below error:

MissingStubError: 'call' No stub was found which matches the arguments of this method call: call(GetGuidFromEmailParams(abc@gmail.com), Instance of 'CancelToken')

removing cancelToken from parameter passes test. How can i solve this issue?

Bloc

Future<void> _onLoginSubmitted(
      _LoginSubmittedEvent event, Emitter<LoginState> emit) async {
    emit(const LoginState.isLoginSubmitted());

    final getGuidParams = GetGuidFromEmailParams(
        email: event.userName);
    final guidRes = await getGuidFromEmailUseCase.call(getGuidParams,_cancelToken);

    if (guidRes.isLeft()) {
      final serverException = (guidRes as Left).value;
      if (isServerSideException(serverException)) {
        emit(LoginState.guidApiCall(GuidApiStatus(
            apiSuccess: false, failureException: serverException)));
      }
    } else {
      await processGuidResponse(emit, event.password);
    }
  }

UseCase

class GetGuidFromEmailUseCase
    extends BaseUseCase<GetGuidRes, GetGuidFromEmailParams> {
  final AuthenticationRepository authenticationRepository;
  final AppSettingRepository appSettingRepository;

  GetGuidFromEmailUseCase(
      {required this.authenticationRepository,
      required this.appSettingRepository});

  @override
  Future<Either<ServerFailuresException, GetGuidRes>> call(
      GetGuidFromEmailParams params,CancelToken cancelToken) async {
    final response = await authenticationRepository.getGuid(
        params.email, cancelToken);

    if (response is Right) {
      final guid = (response as Right).value;
      appSettingRepository.saveGuid(guid);
      appSettingRepository.saveEmail(guid.email!);
    }

    return response;
  }
}
class GetGuidFromEmailParams extends Equatable {
  final String email;

  const GetGuidFromEmailParams(
      {required this.email});

  @override
  List<Object?> get props => [email];
}

TestCase for Bloc

@GenerateMocks(
    [ GetGuidFromEmailUseCase,CancelToken])

blocTest<LoginBloc, LoginState>('_onLoginSubmitted Success',
        build: () {
          final bloc = LoginBloc(
              loginUseCase: mockLoginUseCase,
              getGuidFromEmailUseCase: mockGetGuidFromEmailUseCase,
              appSettingRepository: mockAppSettingRepository);

          const guidParams = GetGuidFromEmailParams(email: email);
          when(bloc.getGuidFromEmailUseCase.call(guidParams,mockCancelToken))
              .thenAnswer((_) async => const Right(guidRes));
          return bloc;
        },
        act: (bloc) =>
            bloc.add(const LoginEvent.onLoginSubmitted(email, password)),
        expect: () => [
          LoginSubmitted(),
          LoginApiCallStatus(
              LoginApiStatus(apiSuccess: true, res: loginRes))
        ]);
srawlins commented 2 years ago

Questions like this are better asked on a forum like StackOverflow.

That being said, I see a stub is created on bloc.getGuidFromEmailUseCase.call with when, but I don't see any real call to call. Where is the real call made? This is the call that must match a stub call.

CharanjeetRPOPS commented 2 years ago
@GenerateMocks(
    [ GetGuidFromEmailUseCase,CancelToken])

blocTest<LoginBloc, LoginState>('_onLoginSubmitted Success',
        build: () {
          final bloc = LoginBloc(
              loginUseCase: mockLoginUseCase,
              getGuidFromEmailUseCase: mockGetGuidFromEmailUseCase,
              appSettingRepository: mockAppSettingRepository);

          const guidParams = GetGuidFromEmailParams(email: email);
          when(bloc.getGuidFromEmailUseCase.call(guidParams,mockCancelToken))
              .thenAnswer((_) async => const Right(guidRes));
          return bloc;
        },
        act: (bloc) =>
            bloc.add(const LoginEvent.onLoginSubmitted(email, password)),
        expect: () => [
          LoginSubmitted(),
          LoginApiCallStatus(
              LoginApiStatus(apiSuccess: true, res: loginRes))
        ]);

in act block, i am calling bloc.add(const LoginEvent.onLoginSubmitted(email, password)) event, call method is invoked in bloc class in _onLoginSubmitted method

Future<void> _onLoginSubmitted(
      _LoginSubmittedEvent event, Emitter<LoginState> emit) async {
    emit(const LoginState.isLoginSubmitted());

    final getGuidParams = GetGuidFromEmailParams(
        email: event.userName);

   // =========================    call method  =========================
    final guidRes = await getGuidFromEmailUseCase.call(getGuidParams,_cancelToken);

    if (guidRes.isLeft()) {
      final serverException = (guidRes as Left).value;
      if (isServerSideException(serverException)) {
        emit(LoginState.guidApiCall(GuidApiStatus(
            apiSuccess: false, failureException: serverException)));
      }
    } else {
      await processGuidResponse(emit, event.password);
    }
  }

Facing error: MissingStubError: 'call' No stub was found which matches the arguments of this method call: call(GetGuidFromEmailParams(abc@gmail.com), Instance of 'CancelToken')

But Removing mockCancelToken from Stub(below code) and everywhere else solves my problem,

when(bloc.getGuidFromEmailUseCase.call(guidParams,mockCancelToken))
.thenAnswer((_) async => const Right(guidRes));

Below is the generated code for call method

@GenerateMocks(
    [ GetGuidFromEmailUseCase,CancelToken])

@override
  _i9.Future<_i4.Either<_i10.ServerFailuresException, _i11.GetGuidRes>> call(
          _i14.GetGuidFromEmailParams? params, _i6.CancelToken? cancelToken) =>
      (super.noSuchMethod(Invocation.method(#call, [params, cancelToken]),
          returnValue:
              Future<_i4.Either<_i10.ServerFailuresException, _i11.GetGuidRes>>.value(
                  _FakeEither_2<_i10.ServerFailuresException,
                      _i11.GetGuidRes>())) as _i9
          .Future<_i4.Either<_i10.ServerFailuresException, _i11.GetGuidRes>>);
srawlins commented 2 years ago

The mockCancelToken is not passed to the bloc = LoginBloc(, so it is not used. Also, I cannot tell where mockCancelToken is declared, or what type it is.

srawlins commented 2 years ago

Please re-open if you can provide more info.