How can I mock/stub out a Flutter platform channel/plugin? How can I mock/stub out a Flutter platform channel/plugin? flutter flutter

How can I mock/stub out a Flutter platform channel/plugin?


You can use setMockMethodCallHandler to register a mock handler for the underlying method channel:

https://docs.flutter.io/flutter/services/MethodChannel/setMockMethodCallHandler.html

final List<MethodCall> log = <MethodCall>[];MethodChannel channel = const MethodChannel('plugins.flutter.io/url_launcher');// Register the mock handler.channel.setMockMethodCallHandler((MethodCall methodCall) async {  log.add(methodCall);});await launch("http://example.com/");expect(log, equals(<MethodCall>[new MethodCall('launch', "http://example.com/")]));// Unregister the mock handler.channel.setMockMethodCallHandler(null);


MethodChannel#setMockMethodCallHandler is deprecated and removed as of now.

Looks like this is the way to go now:

import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart';void mockUrlLauncher() {  const channel = MethodChannel('plugins.flutter.io/url_launcher');  handler(MethodCall methodCall) async {    if (methodCall.method == 'yourMethod') {      return 42;    }    return null;  }  TestWidgetsFlutterBinding.ensureInitialized();  TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger      .setMockMethodCallHandler(channel, handler);}

The details are on GitHub.

And here is a tested example for package_info plugin for future references:

import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart';void mockPackageInfo() {  const channel = MethodChannel('plugins.flutter.io/package_info');  handler(MethodCall methodCall) async {    if (methodCall.method == 'getAll') {      return <String, dynamic>{        'appName': 'myapp',        'packageName': 'com.mycompany.myapp',        'version': '0.0.1',        'buildNumber': '1'      };    }    return null;  }  TestWidgetsFlutterBinding.ensureInitialized();  TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger      .setMockMethodCallHandler(channel, handler);}


When you create a plugin, you are automatically provided a default test:

void main() {  const MethodChannel channel = MethodChannel('my_plugin');  setUp(() {    channel.setMockMethodCallHandler((MethodCall methodCall) async {      return '42';    });  });  tearDown(() {    channel.setMockMethodCallHandler(null);  });  test('getPlatformVersion', () async {    expect(await MyPlugin.platformVersion, '42');  });}

Let me add some notes about it:

  • Calling setMockMethodCallHandler allows you to bypass whatever the actual plugin does and return your own value.
  • You can differentiate methods using methodCall.method, which is a string of the called method name.
  • For plugin creators this is a way to verify the public API names, but it does not test the functionality of the API. You need to use integration tests for that.