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

Mocking Getx controller for flutter widget testing #446

Closed
ghost opened this issue Jul 13, 2021 · 7 comments
Closed

Mocking Getx controller for flutter widget testing #446

ghost opened this issue Jul 13, 2021 · 7 comments
Labels
P2 A bug or feature request we're likely to work on type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@ghost
Copy link

ghost commented Jul 13, 2021

I am getting two exception in the GeneratedMock file:

  1. This exception can be found in the _FakeRx, _FakeRxList and _FakeRxBool
    'Object.==' ('bool Function(Object)') isn't a valid concrete implementation of 'RxObjectMixin.==' ('bool Function(dynamic)').

  2. This exception is given for _i3._InternalFinalCallback
    Classes and mixins can only implement other classes. Try specifying a class or mixin, or remove the name from the list.

How would you solve this issue and why am I getting it? (Sorry if it is something obvious, first time using mockito and getx )

Full code:

// Mocks generated by Mockito 5.0.10 from annotations
// in bloodglucose_monitoring_flutterapp/test/widget/widget_test.dart.
// Do not manually edit this file.

import 'dart:async' as _i6;
import 'dart:ui' as _i7;

import 'package:bloodglucose_monitoring_flutterapp/controller/glucose_controller.dart'
    as _i4;
import 'package:bloodglucose_monitoring_flutterapp/model/glucose.dart' as _i5;
import 'package:get/get_instance/src/lifecycle.dart' as _i3;
import 'package:get/get_rx/src/rx_types/rx_types.dart' as _i2;
import 'package:get/get_state_manager/src/simple/list_notifier.dart' as _i8;
import 'package:mockito/mockito.dart' as _i1;

// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: comment_references
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
// ignore_for_file: unnecessary_parenthesis

class _FakeRx<T> extends _i1.Fake implements _i2.Rx<T> {}

class _FakeRxList<E> extends _i1.Fake implements _i2.RxList<E> {}

class _FakeRxBool extends _i1.Fake implements _i2.RxBool {
  @override
  String toString() => super.toString();
}

class _Fake_InternalFinalCallback<T> extends _i1.Fake
    implements _i3._InternalFinalCallback<T> {}

/// A class which mocks [GlucoseController].
///
/// See the documentation for Mockito's code generation for more information.
class MockGlucoseController extends _i1.Mock implements _i4.GlucoseController {
  MockGlucoseController() {
    _i1.throwOnMissingStub(this);
  }

  @override
  _i2.Rx<_i4.GlucoseListStatus> get getStatus =>
      (super.noSuchMethod(Invocation.getter(#getStatus),
              returnValue: _FakeRx<_i4.GlucoseListStatus>())
          as _i2.Rx<_i4.GlucoseListStatus>);
  @override
  _i2.RxList<DateTime> get getFilteredStartDate =>
      (super.noSuchMethod(Invocation.getter(#getFilteredStartDate),
          returnValue: _FakeRxList<DateTime>()) as _i2.RxList<DateTime>);
  @override
  _i2.RxList<DateTime> get getFilteredEndDate =>
      (super.noSuchMethod(Invocation.getter(#getFilteredEndDate),
          returnValue: _FakeRxList<DateTime>()) as _i2.RxList<DateTime>);
  @override
  _i2.RxList<_i5.Glucose> get getDateFilteredGlucoseList =>
      (super.noSuchMethod(Invocation.getter(#getDateFilteredGlucoseList),
          returnValue: _FakeRxList<_i5.Glucose>()) as _i2.RxList<_i5.Glucose>);
  @override
  _i2.RxList<_i5.Glucose> get getMinimumGlucoseValue =>
      (super.noSuchMethod(Invocation.getter(#getMinimumGlucoseValue),
          returnValue: _FakeRxList<_i5.Glucose>()) as _i2.RxList<_i5.Glucose>);
  @override
  _i2.RxList<_i5.Glucose> get getMaximumGlucoseValue =>
      (super.noSuchMethod(Invocation.getter(#getMaximumGlucoseValue),
          returnValue: _FakeRxList<_i5.Glucose>()) as _i2.RxList<_i5.Glucose>);
  @override
  _i2.RxList<double> get getAverageGlucoseValue =>
      (super.noSuchMethod(Invocation.getter(#getAverageGlucoseValue),
          returnValue: _FakeRxList<double>()) as _i2.RxList<double>);
  @override
  _i2.RxList<double> get getMedianGlucoseValue =>
      (super.noSuchMethod(Invocation.getter(#getMedianGlucoseValue),
          returnValue: _FakeRxList<double>()) as _i2.RxList<double>);
  @override
  _i2.RxBool get getIsMaximumGlucoseValueHover =>
      (super.noSuchMethod(Invocation.getter(#getIsMaximumGlucoseValueHover),
          returnValue: _FakeRxBool()) as _i2.RxBool);
  @override
  _i2.RxBool get getIsMinimumGlucoseValueHover =>
      (super.noSuchMethod(Invocation.getter(#getIsMinimumGlucoseValueHover),
          returnValue: _FakeRxBool()) as _i2.RxBool);
  @override
  bool get hasListeners =>
      (super.noSuchMethod(Invocation.getter(#hasListeners), returnValue: false)
          as bool);
  @override
  int get listeners =>
      (super.noSuchMethod(Invocation.getter(#listeners), returnValue: 0)
          as int);
  @override
  bool get initialized =>
      (super.noSuchMethod(Invocation.getter(#initialized), returnValue: false)
          as bool);
  @override
  bool get isClosed =>
      (super.noSuchMethod(Invocation.getter(#isClosed), returnValue: false)
          as bool);
  @override
  _i3._InternalFinalCallback<void> get onStart =>
      (super.noSuchMethod(Invocation.getter(#onStart),
              returnValue: _Fake_InternalFinalCallback<void>())
          as _i3._InternalFinalCallback<void>);
  @override
  _i3._InternalFinalCallback<void> get onDelete =>
      (super.noSuchMethod(Invocation.getter(#onDelete),
              returnValue: _Fake_InternalFinalCallback<void>())
          as _i3._InternalFinalCallback<void>);
  @override
  _i6.Future<void> onInit() =>
      (super.noSuchMethod(Invocation.method(#onInit, []),
          returnValue: Future<void>.value(),
          returnValueForMissingStub: Future.value()) as _i6.Future<void>);
  @override
  void dispose() => super.noSuchMethod(Invocation.method(#dispose, []),
      returnValueForMissingStub: null);
  @override
  void setFilteredStartDate(DateTime? startDate) =>
      super.noSuchMethod(Invocation.method(#setFilteredStartDate, [startDate]),
          returnValueForMissingStub: null);
  @override
  void setFilteredEndDate(DateTime? endDate) =>
      super.noSuchMethod(Invocation.method(#setFilteredEndDate, [endDate]),
          returnValueForMissingStub: null);
  @override
  void setIsMaximumGlucoseValueHover() =>
      super.noSuchMethod(Invocation.method(#setIsMaximumGlucoseValueHover, []),
          returnValueForMissingStub: null);
  @override
  void setIsMinimumGlucoseValueHover() =>
      super.noSuchMethod(Invocation.method(#setIsMinimumGlucoseValueHover, []),
          returnValueForMissingStub: null);
  @override
  _i6.Future<void> postGlucoseData() =>
      (super.noSuchMethod(Invocation.method(#postGlucoseData, []),
          returnValue: Future<void>.value(),
          returnValueForMissingStub: Future.value()) as _i6.Future<void>);
  @override
  _i6.Future<void> saveGlucoseData() =>
      (super.noSuchMethod(Invocation.method(#saveGlucoseData, []),
          returnValue: Future<void>.value(),
          returnValueForMissingStub: Future.value()) as _i6.Future<void>);
  @override
  void update([List<Object>? ids, bool? condition = true]) =>
      super.noSuchMethod(Invocation.method(#update, [ids, condition]),
          returnValueForMissingStub: null);
  @override
  void refresh() => super.noSuchMethod(Invocation.method(#refresh, []),
      returnValueForMissingStub: null);
  @override
  void refreshGroup(Object? id) =>
      super.noSuchMethod(Invocation.method(#refreshGroup, [id]),
          returnValueForMissingStub: null);
  @override
  void notifyChildrens() =>
      super.noSuchMethod(Invocation.method(#notifyChildrens, []),
          returnValueForMissingStub: null);
  @override
  void removeListener(_i7.VoidCallback? listener) =>
      super.noSuchMethod(Invocation.method(#removeListener, [listener]),
          returnValueForMissingStub: null);
  @override
  void removeListenerId(Object? id, _i7.VoidCallback? listener) =>
      super.noSuchMethod(Invocation.method(#removeListenerId, [id, listener]),
          returnValueForMissingStub: null);
  @override
  _i8.Disposer addListener(_i8.GetStateUpdate? listener) =>
      (super.noSuchMethod(Invocation.method(#addListener, [listener]),
          returnValue: () {}) as _i8.Disposer);
  @override
  _i8.Disposer addListenerId(Object? key, _i8.GetStateUpdate? listener) =>
      (super.noSuchMethod(Invocation.method(#addListenerId, [key, listener]),
          returnValue: () {}) as _i8.Disposer);
  @override
  void disposeId(Object? id) =>
      super.noSuchMethod(Invocation.method(#disposeId, [id]),
          returnValueForMissingStub: null);
  @override
  void onReady() => super.noSuchMethod(Invocation.method(#onReady, []),
      returnValueForMissingStub: null);
  @override
  void onClose() => super.noSuchMethod(Invocation.method(#onClose, []),
      returnValueForMissingStub: null);
  @override
  void $configureLifeCycle() =>
      super.noSuchMethod(Invocation.method(#$configureLifeCycle, []),
          returnValueForMissingStub: null);
}

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.2.3, on macOS 11.4 20F71 darwin-x64, locale en-LK)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
[✓] Xcode - develop for iOS and macOS
[✓] Chrome - develop for the web
[✓] Android Studio (version 4.1)
[✓] IntelliJ IDEA Community Edition (version 2021.1.1)
[✓] VS Code (version 1.58.0)
[✓] Connected device (1 available)
@ghost ghost changed the title Mocking Getx controller for flutter testing Mocking Getx controller for flutter widget testing Jul 13, 2021
@srawlins
Copy link
Member

This exception can be found in the _FakeRx, _FakeRxList and _FakeRxBool
'Object.==' ('bool Function(Object)') isn't a valid concrete implementation of 'RxObjectMixin.==' ('bool Function(dynamic)').

I suspect this problem is fixed in a recent version of get. At HEAD, you can see that RxObjectMixin.== accepts an Object instead of dynamic: https://github.com/jonataslaw/getx/blob/master/lib/get_rx/src/rx_types/rx_core/rx_impl.dart#L84

implements _i3._InternalFinalCallback {}

Ouch, mockito should definitely throw rather than generate this code. In any case, the problem is that GlucoseController has methods which seem to reference private types: get onStart and get onDelete return _InternalFinalCallback<void> which we can't mock...

You might be able to get around this shortcoming by specifying your own fallback generators (in customMocks for these two methods. These are a new API so not documented super well. You can find an example in the tests.

@srawlins
Copy link
Member

srawlins commented Aug 11, 2021

Indeed it looks like the get authors do not want GetLifeCycle to be subclassed, as per onStart:

It uses an internal "callable" type, to avoid any @overrides in subclases. This method should be internal and is required to define the lifetime cycle of the subclass.

I understand that you are likely not overriding the getter, but mockito needs to, in order to return a non-null value.

@srawlins srawlins added type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) P2 A bug or feature request we're likely to work on labels Aug 11, 2021
@kuhnroyal
Copy link
Contributor

The changes related to this issue broke quite a few of my mocks which previously worked.
I understand that I probably have not used the broken generated methods and that is why they work.
But this is likely a breaking change for a lot of projects and should not be patch version.

@srawlins
Copy link
Member

@kuhnroyal You may have responded to the wrong issue. I don't see how your comments relate to this issue...

The changes related to this issue broke

What changes?

But this is likely a breaking change

What is?

@kuhnroyal
Copy link
Contributor

You linked it in the changelog for 5.0.17 - in any case, that version breaks builds and it looks like this fits as I suddenly have invalid mocks.

@srawlins
Copy link
Member

Ah I understand. Thanks for the info. Can you please file an issue with the problem with a reproduction case? Including the mocks-in-question generated by 5.0.16 and the error reported by 5.0.17 would be very helpful. Thanks!

@fauzipadlaw
Copy link

solution for this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
P2 A bug or feature request we're likely to work on type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

3 participants