dart 如何模拟/清除Flutter平台的通道/插件?

bvpmtnay  于 2023-09-28  发布在  Flutter
关注(0)|答案(4)|浏览(154)

我在Flutter网站上阅读了introduction to platform-specific plugins/channels,并浏览了一些简单的插件示例,如url_launcher

// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

import 'package:flutter/services.dart';

const _channel = const MethodChannel('plugins.flutter.io/url_launcher');

/// Parses the specified URL string and delegates handling of it to the
/// underlying platform.
///
/// The returned future completes with a [PlatformException] on invalid URLs and
/// schemes which cannot be handled, that is when [canLaunch] would complete
/// with false.
Future<Null> launch(String urlString) {
  return _channel.invokeMethod(
    'launch',
    urlString,
  );
}

在小部件测试或集成测试中,我如何模拟或存根通道,这样我就不必依赖于真实的的设备(运行Android或iOS),比如实际启动URL?

twh00eeo

twh00eeo1#

MethodChannel#setMockMethodCallHandler已弃用并已删除。
看起来这是现在要走的路:

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

详细信息在GitHub上。
下面是package_info插件的测试示例,供将来参考:

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

t98cgbkg2#

您可以使用setMockMethodCallHandler为底层方法通道注册一个模拟处理程序:
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.
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
          .setMockMethodCallHandler(channel, (message) {
  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);
eaf3rand

eaf3rand3#

当你创建一个插件时,系统会自动为你提供一个默认测试:

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

让我添加一些关于它的注解:

  • 调用setMockMethodCallHandler可以让你绕过实际插件所做的任何事情,并返回你自己的值。
  • 您可以使用methodCall.method来区分方法,methodCall.method是被调用方法名称的字符串。
  • 对于插件创建者来说,这是一种验证公共API名称的方法,但它不会测试API的功能。您需要使用集成测试来实现这一点。
vwoqyblh

vwoqyblh4#

在我的情况下,我的频道是私人的,所以我无法访问它。总的来说,我有这样的东西:

testWidgets('My test', (WidgetTester tester) async {
    //https://github.com/flutter/flutter/issues/76790 - add delay work around
    await tester.runAsync(() async {
      //arrange
      MethodChannel channel = const MethodChannel('my_channel');
      WidgetsFlutterBinding.ensureInitialized();
        tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, (message) => null);
      await Future.delayed(Duration(milliseconds: 400));
    });
  });

相关问题