如何为Flutter测试模拟url_launcher包?

3
我在我的Flutter项目中使用了 url_launcher: ^6.1.0。 我开始为我的小部件编写测试,但使用 url_launcher 方法启动URL的部分在运行测试时无法正常工作。
我在小部件中使用的其中一种方法如下:
 Future<void> _onTapLink(String? href) async {
    if (href == null) return;

    // canLaunchUrl method never return anything when we are calling this function inside flutter test
    if (await canLaunchUrl(Uri.parse(href))) {
      await launchUrl(Uri.parse(href));
    } else {
      print('cannot launch url: $href');
    }
  }

canLaunchUrl方法在Flutter测试中调用时不会返回任何内容。

我正在寻找一种方法来模拟url_launcher包,以便在Flutter测试中使用。


尝试使用此答案:这里 - Ravindra S. Patil
@RavindraS.Patil,对我来说没有用,当我运行测试覆盖率时,它显示canLaunch方法的结果从未返回。 - Taleb
2
我认为唯一的方法是将launchURL和canLaunchURL方法封装在自己的类中。然后你就可以在测试中模拟这个类。将外部库放在门面后面总是一个好主意。 - A.K.
2个回答

3

要模拟 url_launcher,您可以:

  1. plugin_platform_interfaceurl_launcher_platform_interface 包添加到 pubspec.yaml 文件的 dev_dependencies 部分。
  2. 实现模拟类。例如,使用 mocktail 的实现如下:
import 'package:mocktail/mocktail.dart';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart';

class MockUrlLauncher extends Mock
    with MockPlatformInterfaceMixin
    implements UrlLauncherPlatform {}

请注意这里使用了MockPlatformInterfaceMixin混入。
3. 像往常一样配置模拟。对于mocktail,可能是这样的:
MockUrlLauncher setupMockUrlLauncher() {
  final mock = MockUrlLauncher();
  registerFallbackValue(const LaunchOptions());

  when(() => mock.launchUrl(any(), any())).thenAnswer((_) async => true);
  return mock;
}
  1. 通过在 UrlLauncherPlatform.instance 中设置,告诉 url_launcher 使用模拟版本:
final mock = setupMockUrlLauncher();
UrlLauncherPlatform.instance = mock;

1

这篇文章详细解释了如何模拟或伪造launchUrl函数。以下是使用mocktail进行模拟的示例。它还使用ioc_container包来处理依赖注入的替换。

import 'package:fafsdfsdf/main.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter/material.dart';

class LaunchMock extends Mock {
  Future<bool> call(
    Uri url, {
    LaunchMode? mode,
    WebViewConfiguration? webViewConfiguration,
    String? webOnlyWindowName,
  });
}

void main() {
  testWidgets('Test Url Launch', (tester) async {
    //These allow default values
    registerFallbackValue(LaunchMode.platformDefault);
    registerFallbackValue(const WebViewConfiguration());

    //Create the mock
    final mock = LaunchMock();
    when(() => mock(
          flutterDevUri,
          mode: any(named: 'mode'),
          webViewConfiguration: any(named: 'webViewConfiguration'),
          webOnlyWindowName: any(named: 'webOnlyWindowName'),
        )).thenAnswer((_) async => true);

    final builder = compose()
      //Replace the launch function with a mock
      ..addSingletonService<LaunchUrl>(mock);

    await tester.pumpWidget(
      builder.toContainer()<MyApp>(),
    );

    //Tap the icon
    await tester.tap(
      find.byIcon(Icons.favorite),
    );

    await tester.pumpAndSettle();

    verify(() => mock(flutterDevUri)).called(1);
  });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接