Search code examples
flutterunit-testing

Flutter Mocktail registerFallbackValue doesn't register the value


I have a class that I want to mock, in the non-test code there's a method with the method signature:

Future downloadDataItem({
    required String path,
    Function(
      double? progress,
      int current,
      int? total,
    )? onProgress,
    required Function(List<int> bytes) onDone,
    required Function(dynamic error) onError,
  })

Which is called like this:

_downloadManager.downloadDataItem(
      path: avatarPath,
      onDone: (bytes) async {
        if (bytes.isNotEmpty) {
          await _fileManager.saveDataFile(avatarPath, bytes);
        }
        final file = await _fileManager.getDataFile(avatarPath);
        onDone(file);
      },
      onError: (error) {
        dLog('error: $error');
      },
    );

Before the tests are run I also register the values so it understands what any() could be

    registerFallbackValue((bytes) async { });
    registerFallbackValue((error) {});
    registerFallbackValue('');

In the test class I use the when method to setup the mock method to read a local image for testing purposes.

    when(
      () => manager.downloadDataItem(
        path: path,
        onDone: any(),
        onError: any(),
      ),
    ).thenAnswer((invocation) async {
      final path = invocation.namedArguments['path'];
      ByteData bytes = await rootBundle.load(path);
      return bytes;
    });

I then get the error output:

Invalid argument(s): An argument matcher (like `any()`) was either not used as an immediate argument
to Symbol("downloadDataItem") (argument matchers can only be used as an argument for the very method
being stubbed or verified), or was used as a named argument without the Mocktail "named" API (Each
argument matcher that is used as a named argument needs to specify the name of the argument it is
being used in. For example: `when(() => obj.fn(x: any(named: "x")))`).

Why is it giving me this error when I told it that any() could be a string or one of the two functions?

From what I can tell, I should be able to use any() whenever I attach a mock function with when and tell Mocktail what types to expect in the any() with the registerFallbackValue methods. This is how I've done it in other tests.

I also made a class and used that in the register as well, but it doesn't work.

class _Functions {
  void onDone(List<int> bytes) async {}
  void onError(dynamic error) {}
}

With registration like so:

    registerFallbackValue(_Functions().onDone);
    registerFallbackValue(_Functions().onError);
    registerFallbackValue('');

Is there some sort of different trick required when method arguments are functions?


Solution

  • The error message is telling exactly what's going wrong:

    or was used as a named argument without the Mocktail "named" API (Each
    argument matcher that is used as a named argument needs to specify the name of 
    the argument it is
    being used in. For example: `when(() => obj.fn(x: any(named: "x")))`)
    

    You need to use the named parameter in any()