flutterdartunit-testingmockito

Why does verify(() => mockObject.someGetter) throw 'Used on a non-mockito object' even though the object is a Mock?


I'm currently writing unit tests for a Flutter app using mockito, and I'm running into an issue with verifying a getter call using the latest version of mockito (v5.x).

Here's my test setup:

@GenerateMocks([InternetConnectionChecker])
void main() {
  late MockInternetConnectionChecker internetConnectionChecker;
  late NetworkInfoImpl networkInfo;

  setUp(() {
    internetConnectionChecker = MockInternetConnectionChecker();
    networkInfo = NetworkInfoImpl(internetConnectionChecker);
  });

  test('should check internet connection', () async {
    // Arrange
    when(() => internetConnectionChecker.hasConnection)
        .thenAnswer((_) async => true);

    // Act
    final result = await networkInfo.isConnect;

    // Assert
    verify(() => internetConnectionChecker.hasConnection); // ❌ Throws error
    expect(result, true);
  });
}

error test mockito

Even though internetConnectionChecker is clearly a MockInternetConnectionChecker, the test throws this error:

Used on a non-mockito object
package:matcher                                 fail
package:mockito/src/mock.dart 1155:7            _makeVerify.<fn>
test\core\network\network_info_test.dart 30:13  main.<fn>.<fn>

However, if I write it like this, it works:

verify(internetConnectionChecker.hasConnection); // ✅ Works, but discouraged?

enter image description here From what I understand, using verify(() => ...) is the recommended way to ensure that the method or getter was actually called. So why does this error happen?

Is there something special about getters in the latest versions of mockito? Or has there been a breaking change that I missed?


Solution

  • when requires a method call to be recorded on a Mockito mock instance. Same goes for verify.

    When you write when(() => internetConnectionChecker.hasConnection) or verify(() => internetConnectionChecker.hasConnection), you are not calling a method. You are passing a lambda instead.

    A lambda is not a mock (it's a lambda. yourMock is a mock, but () => yourMock is not a mock. yourMock.method() calls a method on your mock, () => yourMock.method() does not call the method on your mock. It wraps it in a lambda to be invoked at a later point in time).

    Passing a lambda will not invoke the lambda and consequently not call the method on your mock.

    Check the Flutter docs for example how to set up your mocks with when:

          when(
            client.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1')),
          ).thenAnswer((_) async => http.Response('Not Found', 404));
    

    or how to verify the calls on your mocks:

    cat.eatFood("chicken");
    verify(cat.eatFood("fish"));