How do I stub a function that does not belong to a class, during a widget test?
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;
}
Bakkingamu
Updated on December 13, 2022Comments
-
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 theavailableCameras
function from the package and aFloatingActionButton
which takes a photo when pressed. While creating a widget test for this modal, I can not figure out how to stub theavailableCameras
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 almost 5 yearsVery 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 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 almost 5 yearsThere are entire books dedicated to these patterns, so I can't reasonably give a definitive solution here.
-
Hugo Passos almost 5 yearsYeah, 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 almost 5 yearsYou 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 almost 5 yearsYou're right. I initially thought
availableCameras
was called by the library, not by the user. -
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.