Search code examples
flutterunit-testingriverpod

Use Mockito for a Riverpod AsyncValue call in Flutter/Dart


I am testing some Flutter/Dart code with an AsyncValue provider. I am using Andrea's example almost literally. My listener extends Mock but when I verify it the test fails with 'Used on a non-mockito object'.

Which non-mockito object is this talking about? My listener is a mock.

import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:riverpod/riverpod.dart';

// a generic Listener class, used to keep track of when a provider
// notifies its listeners
class Listener<T> extends Mock {
  void call(T? previous, T next);
}

void main() {
  group('GeoData', () {
    // This is a variation of Andrea's AuthController example minus the
    // extra mock'ed AuthRepository dependency.
    // https://codewithandrea.com/articles/unit-test-async-notifier-riverpod/
    test('initialization with default GeoInfo data', () {
      final container = ProviderContainer();
      addTearDown(container.dispose);
      final listener = Listener<AsyncValue<GeoInfo>>();

      container.listen(geoDataProvider, listener, fireImmediately: true);

      // ---> this is the line that fails the test with "Used on a non-mockito object"
      verify(() => listener(null, const AsyncData<GeoInfo>(GeoInfo.empty())));
      verifyNoMoreInteractions(listener);
    });
  });
}
'''

Solution

  • Yikes, I spent way too much time on this and went down more than one rabbit hole before I found it. This has nothing to do with initializing the mock wrongly and everything with the difference between mocktail and mockito 🤦‍♀️

    The two packages are very similar but the syntax for the verify call is different.

    Mocktail: verify(() => listener(null, const AsyncData<GeoInfo>(GeoInfo.empty())));

    Mockito: verify(listener.call(null, const AsyncData<GeoInfo>(GeoInfo.empty()))).called(1);

    Once I changed my call to the Mockito syntax the test passed as expected.