mockito Flutter试验中如何模拟功能

z4iuyo4d  于 2022-11-23  发布在  Flutter
关注(0)|答案(2)|浏览(175)

如何在flutter中模拟一个函数并验证它已经被调用了n次?
我试过从mockito实现Mock,但它只抛出错误:

class MockFunction extends Mock {
  call() {}
}

test("onListen is called once when first listener is registered", () {
      final onListen = MockFunction();

      // Throws: Bad state: No method stub was called from within `when()`. Was a real method called, or perhaps an extension method?
      when(onListen()).thenReturn(null);

      bloc = EntityListBloc(onListen: onListen);

      // If line with when call is removed this throws:
      // Used on a non-mockito object
      verify(onListen()).called(1);
    });

  });

作为一种解决方法,我只是手动跟踪呼叫:

test("...", () {
   int calls = 0;
   bloc = EntityListBloc(onListen: () => calls++);

   // ...

   expect(calls, equals(1));
});

那么,有没有一种方法可以为Flutter测试创建简单的模拟函数呢?

8qgya5xd

8qgya5xd1#

你可以这样做:

class Functions  {
  void onListen() {}
}

class MockFunctions extends Mock implements Functions {}

void main() {
  test("onListen is called once when first listener is registered", () {
    final functions = MockFunctions();

    when(functions.onListen()).thenReturn(null);

    final bloc = EntityListBloc(onListen: functions.onListen);

    verify(functions.onListen()).called(1);
  });
}
bvjveswy

bvjveswy2#

公认的答案是正确的,但它并不代表您可能希望用mock或fake替换顶级函数的真实场景。This article解释了如何在依赖注入组合中包含顶级函数,以便可以用mock替换这些函数。
您可以像这样编写依赖注入,并指向顶级函数,例如launchUrlioc_container

IocContainerBuilder compose() => IocContainerBuilder(
      allowOverrides: true,
    )
      ..addSingletonService<LaunchUrl>(
        (url, {mode, webOnlyWindowName, webViewConfiguration}) async =>
            launchUrl(
          url,
          mode: mode ?? LaunchMode.platformDefault,
          webViewConfiguration:
              webViewConfiguration ?? const WebViewConfiguration(),
          webOnlyWindowName: webOnlyWindowName,
        ),
      )
      ..add((container) => MyApp(launchUrl: container<LaunchUrl>()));

然后,你可以使用这里的答案中提到的技巧来用Mocktail进行模拟。

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

相关问题