Reputation: 753
I have a flutter plugin which uses the platform channel to do some native work.
How do I properly write tests for my application that requires this plugin?
Unit tests only are good for pure dart functions. I don't believe Widget testing will be able to test things that use the platform channel to native. So that leaves integration testing.
From what I understand is that integration testing will start your main application and you can control it around your app and test things.
For my case, I want to test just the code that uses the plugin (that uses the platform channel for native stuff).
Also what is important is the values that come back from the platform channel, so it is important to call the native side using a real platform channel and not a mock one.
Is that possible? Can I tell the integration tester to open a dummy version of my application, kind of like an integrated widget tester?
Upvotes: 17
Views: 6701
Reputation: 203
One additional thing to @呂學洲 answer.. is if you're writing a unit test and don't have reference to widget tester instance you can access the binder like below
TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger
Also make sure to wait for binder to initialize in the begging of the test like below
TestWidgetsFlutterBinding.ensureInitialized();
And to grab method call you can do:
final binaryBinding = TestDefaultBinaryMessengerBinding.instance;
pluginChannel = MethodChannel('channelName');
binaryBinding!.defaultBinaryMessenger.setMockMethodCallHandler(pluginChannel,
(MethodCall methodCall) async {
switch (methodCall.method) {
case 'call 1':
return mockValue;
default:
return null;
}
},
);
Hope that helps.
Upvotes: 2
Reputation: 1413
Flutter team do mentions that they want to do more things in widgets test instead of driver(integration) test.
We're moving away from flutter_driver in favour of extending flutter_test to work on devices.
From Flutter 2.8 breaking changes doc, you should use binding
in tester
instead of setMockMethodCallHandler
from channel.
// old code
myMethodChannel.setMockMethodCallHandler(...);
myMethodChannel.checkMockMethodCallHandler(...);
// new code
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(myMethodChannel, ...);
tester.binding.defaultBinaryMessenger.checkMockMessageHandler(myMethodChannel, ...);
Take ImagePicker as example:
widgetTest('', (tester) async {
const channel = MethodChannel('plugins.flutter.io/image_picker');
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
channel,
(MethodCall methodCall) => Future.value('some-image'),
);
});
Upvotes: 2
Reputation: 2309
It seems the short answer to your question is no. Flutter driver (integration testing) can only interact with the UI, AFAIK. It cannot intercept calls to plugins. It is used to test the entire app from the UI.
However it is possible to intercept calls to plugins in unit and widget tests. This allows monitoring the calls to the plugin and mocking the response. That way you can test your plugin's dart code and/or a widget that uses the plugin. Testing native code would involve writing native tests.
The following is an example of intercepting calls to a plugin for testing:
MethodChannel('audio_recorder')
.setMockMethodCallHandler((MethodCall methodCall) async {
log.add(methodCall);
switch (methodCall.method) {
case 'start':
isRecording = true;
return null;
case 'stop':
isRecording = false;
return {
'duration': duration,
'path': path,
'audioOutputFormat': extension,
};
case 'isRecording':
return isRecording;
case 'hasPermissions':
return true;
default:
return null;
}
});
For a complete example see here
Upvotes: 17