如何在 Flutter 中为多个测试“设置"一个“WidgetTester" [英] How to `setUp` a `WidgetTester` for Multiple Tests in Flutter

查看:18
本文介绍了如何在 Flutter 中为多个测试“设置"一个“WidgetTester"的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

testWidgets 函数显然只是 test 函数的子案例.

The testWidgets function is apparently only a subcase of the test function.

我现在要解决的一个用例是为多个 testWidgets 泵送同一个小部件,为多个 testWidgets 泵送一个 setUp.但是,如果它在每个测试中创建一个新实例,我该怎么做?

A use case I'm trying to solve right now is to pump the same widget for multiple testWidgets, a setUp for multiple testWidgets. However, how can I do this if it creates a new instance inside each test?

我试图在测试之外的 main() 中初始化一个 WidgetTester,但 WidgetTester 只有一个私有构造函数:

I've tried to initialize a WidgetTester outside the tests, in the main(), but WidgetTester has only a private constructor:

class WidgetTester 
  extends WidgetController 
    implements HitTestDispatcher, TickerProvider {
  WidgetTester._(TestWidgetsFlutterBinding binding) : super(binding) {
    if (binding is LiveTestWidgetsFlutterBinding)
      binding.deviceEventDispatcher = this;
}

我不太明白 Flutter 团队是如何完成这项工作的,但是以与在 testWidgets 函数中相同的方式初始化 WidgetTester 并不适用我:

I don't quite get how the Flutter team made this work, but initializing a WidgetTester in the same way they did inside the testWidgets function isn't working for me:

final TestWidgetsFlutterBinding binding 
  = TestWidgetsFlutterBinding.ensureInitialized() 
    as TestWidgetsFlutterBinding;
final WidgetTester tester = WidgetTester._(binding);

2.一个例子

一个简单的例子是尝试分解使用 flutter create 中的每个新 Flutter 项目创建的 Flutter 演示的测试.在其中,我们可以尝试将应用程序的初始设置测试与点击动作测试分开:

2. An Example

A simple example would be to try to break down the tests of the Flutter demo that is created with each new Flutter project from flutter create. In it, we could try to separate the initial setup test of the app from the tapping action test:

testWidgets('Initial setup', (WidgetTester tester) async {
  await tester.pumpWidget(MyApp());

  expect(find.text('0'), findsOneWidget);
  expect(find.text('1'), findsNothing);
});

testWidgets('Increment the counter on tap', (WidgetTester tester) async {
  await tester.pumpWidget(MyApp());

  await tester.tap(find.byIcon(Icons.add));
  await tester.pump();

  expect(find.text('0'), findsNothing);
  expect(find.text('1'), findsOneWidget);
});

我们的想法是尝试将 await tester.pumpWidget(MyApp()); 移动到 setUp 函数中.

The idea would be to try to move the await tester.pumpWidget(MyApp()); into a setUp function.

推荐答案

下面是目前在 Flutter 中解决这个问题的方法.

Below is what looks like the current way to solve for this in Flutter.

总结一下:

  1. main()
  2. 中创建 group(..) 结构
  3. 从该结构内部为您想要的每组测试创建您自己的私有方法.对于这些私有方法中的每一个:
    • 传入 WidgetTester 实例
    • 让它们异步
  1. Create the group(..) structure inside main()
  2. Create your own private methods from inside that structure, for each group of testing you want. For each of these private methods:
    • Pass in the WidgetTester instance
    • Let them be async
  • 在这个方法中,你可以调用你设置的私有方法来分发测试逻辑
  • await 调用每一个,这样它们就不会同时运行
  • Inside this method, is where you call the private methods you set up to distribute test logic
  • Call each of these with await, so they don't run concurrently

<小时>

到目前为止,我还没有找到一种方法让输出指示每个子测试".它运行了,所以现在只使用 print(...) 语句.

这是一些二维码逻辑的演示:

This is a demo for some QR Code logic:

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:qr_code_demo/app/appRoutes.dart';
import 'package:qr_code_demo/view/appHome.dart';
import 'package:qr_code_demo/view/qrScanner.dart';

class MockNavigatorObserver extends Mock implements NavigatorObserver {}

void main() {
  group('MainPage navigation tests', () {
    NavigatorObserver mockObserver;

    _loadAppHomeScreen(WidgetTester tester) async {
      await tester.pumpWidget(
        MaterialApp(
          routes: AppRoutes.getRouteMap(),
          home: AppHomeScreen(),
          navigatorObservers: [mockObserver],
        ),
      );
    }

    setUp(() {
      mockObserver = MockNavigatorObserver();
    });

    Future<Null> _verifyLayoutElements(WidgetTester tester) async {
      print('_verifyLayoutElements');
      expect(find.byIcon(Icons.scanner), findsOneWidget);
      expect(find.byType(FloatingActionButton), findsOneWidget);
      expect(find.byType(RaisedButton), findsOneWidget);
    }

    Future<Null> _navigateToQrScannerScreen(WidgetTester tester) async {
      print('_navigateToQrScannerScreen');

      await tester.tap(find.byIcon(Icons.scanner));
      await tester.pumpAndSettle();

      verify(mockObserver.didPush(any, any));

      expect(find.byType(AppHomeScreen), findsNothing);
      expect(find.byType(QrScannerScreen), findsOneWidget);
    }

    testWidgets('AppHomeScreen WidgetTester', (WidgetTester tester) async {
      await _loadAppHomeScreen(tester);

      await _verifyLayoutElements(tester);
      await _navigateToQrScannerScreen(tester);
    });
  });
}

感谢:https://iiro.dev/2018/08/22/writing-widget-tests-for-navigation-events/

  • 滚动到该文件的代码:test/navigation_test.dart

====

再次感谢,因为包含此示例的导航测试逻辑要感谢 @iiro 的帖子:https://stackoverflow.com/a/51983194/2162226

And double-thanks, because the navigation testing logic including with this example is thanks to @iiro's post: https://stackoverflow.com/a/51983194/2162226

这是 appRoutes.dart 文件:

import 'package:qr_code_demo/view/appHome.dart';
import 'package:qr_code_demo/view/qrScanner.dart';  

class AppRoutes {

  static const String AppHome = 'AppHome';
  static const String QrScanner = 'QrScanner';

  static String initialRoute() {
    return AppHome;
  }
  
  static getRouteMap() {
    
    return {
      AppRoutes.AppHome: (context) => AppHomeScreen(),
      AppRoutes.QrScanner: (context) => QrScannerScreen()
    };
    
  }
}

这篇关于如何在 Flutter 中为多个测试“设置"一个“WidgetTester"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆