测试使用插件和平台通道的 Flutter 代码

Testing Flutter code that uses a plugin and platform channel

我有一个 flutter 插件,它使用平台通道来做一些本地工作。

如何为需要此插件的应用程序正确编写测试?

仅单元测试适用于纯 dart 函数。我不相信 Widget 测试能够测试使用平台通道到本地的东西。这样就剩下集成测试了。

据我了解,集成测试将启动您的主应用程序,您可以围绕您的应用程序控制它并进行测试。

对于我的情况,我只想测试使用插件的代码(使用原生内容的平台通道)。

同样重要的是从平台通道返回的值,因此使用真实的平台通道而不是模拟通道调用本机端很重要。

这可能吗?我可以告诉集成测试器打开我的应用程序的虚拟版本,有点像集成小部件测试器吗?

您的问题的简短答案似乎是否定的。 Flutter 驱动程序(集成测试)只能与 UI、AFAIK 交互。它无法拦截对插件的调用。它用于从 UI.

测试整个应用程序

但是,可以在单元和小部件测试中拦截对插件的调用。这允许监视对插件的调用并模拟响应。这样你就可以测试你的插件的飞镖代码 and/or 一个使用插件的小部件。测试本机代码将涉及编写本机测试。

以下是拦截插件调用测试的例子:

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;
  }
});

有关完整示例,请参阅 here

Flutter 团队 mentions 他们想在小部件测试而不是驱动程序(集成)测试中做更多的事情。

We're moving away from flutter_driver in favour of extending flutter_test to work on devices.

来自 Flutter 2.8 的重大更改 doc, you should use binding in tester 而不是来自频道的 setMockMethodCallHandler

// old code
myMethodChannel.setMockMethodCallHandler(...);
myMethodChannel.checkMockMethodCallHandler(...);
// new code
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(myMethodChannel, ...);
tester.binding.defaultBinaryMessenger.checkMockMessageHandler(myMethodChannel, ...);

ImagePicker为例:

widgetTest('', (tester) async {
  const channel = MethodChannel('plugins.flutter.io/image_picker');
  tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
    channel,
    (MethodCall methodCall) => Future.value('some-image'),
  );
});

@吕学洲回答的另外一件事.. 如果您正在编写单元测试并且没有对小部件测试器实例的引用,您可以访问下面的活页夹

TestDefaultBinaryMessengerBinding.instance!.defaultBinaryMessenger

还要确保在测试开始时等待 binder 初始化,如下所示

TestWidgetsFlutterBinding.ensureInitialized();

要获取方法调用,您可以这样做:

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;
    }
  },
);

希望对您有所帮助。