How do I stub a function that does not belong to a class, during a widget test?

4,731

Solution 1

Mockito can mock functions too. In dart, functions are classes with a call method.

You can, therefore, use Mockito as usual, with an abstract call method:

class MockFunction extends Mock {
  int call(String param);
}

This example represents a int Function(String param).

Which means you can then do:

final int Function(String) myFn = MockFunction();
when(myFn('hello world')).thenReturn(42);

expect(myFn('hello world'), equals(42));

Solution 2

In this very specific situation, you can mock the method channel call handler.

const cameraMethodChannel = MethodChannel('plugins.flutter.io/camera');

setUpAll(() {
  cameraMethodChannel.setMockMethodCallHandler(cameraCallHandler);
});

tearDownAll(() {
  cameraMethodChannel.setMockMethodCallHandler(null);
});

Future<dynamic> cameraCallHandler(MethodCall methodCall) async {
  if (methodCall.method == 'availableCameras') return yourListOfCameras;
}
Share:
4,731
Bakkingamu
Author by

Bakkingamu

Updated on December 13, 2022

Comments

  • Bakkingamu
    Bakkingamu over 1 year

    I am creating a flutter app that uses the native camera to take a photo, using the official flutter camera package (https://pub.dev/packages/camera). The app opens up a modal that loads a CameraPreview based on the the result of the availableCameras function from the package and a FloatingActionButton which takes a photo when pressed. While creating a widget test for this modal, I can not figure out how to stub the availableCameras function to return what I want during tests.

    I tried using the Mockito testing package, but this only supports mocking classes. Since this function does not belong to a class, I cannot mock it.

    The availableCameras function returns a list of cameras that the device has. I want to be able to control what comes back from this function, so that I may test how my widget reacts to different cameras. What is the proper way to have this function return what I want during a widget test?

  • Hugo Passos
    Hugo Passos almost 5 years
    Very interesting, but wouldn't this work only if the function was injected (as an argument, for instance)? Can you please provide an example of mocking a top-level function?
  • Rémi Rousselet
    Rémi Rousselet almost 5 years
    @HugoPassos yes, you need a mean to replace the function with another. There are tons of different ways to do so though. For example, the function could be a mutable global variable.
  • Rémi Rousselet
    Rémi Rousselet almost 5 years
    There are entire books dedicated to these patterns, so I can't reasonably give a definitive solution here.
  • Hugo Passos
    Hugo Passos almost 5 years
    Yeah, but we're talking about a public library. I can't think in any way to replace the function in this situation.
  • Rémi Rousselet
    Rémi Rousselet almost 5 years
    You don't have to use the function directly. A global var getCameras = availableCameras should do the trick. Then your test can replace it with a different value.
  • Hugo Passos
    Hugo Passos almost 5 years
    You're right. I initially thought availableCameras was called by the library, not by the user.
  • kabayaba
    kabayaba almost 4 years
    @HugoPassos may i check you resolved this issue? i called availableCameras() inside my real bloc class but have no idea how to mock it.