【问题标题】:How to `setUp` a `WidgetTester` for Multiple Tests in Flutter如何在 Flutter 中为多个测试“设置”一个“WidgetTester”
【发布时间】:2020-06-06 21:29:07
【问题描述】:

1。问题

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

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

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

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

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

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

2。一个例子

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

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 函数中。

【问题讨论】:

    标签: testing flutter dart widget


    【解决方案1】:

    下面是目前在 Flutter 中解决此问题的方法。

    总结一下:

    1. main() 内创建group(..) 结构
    2. 从该结构内部为您想要的每组测试创建您自己的私有方法。对于这些私有方法中的每一个:
      • 传入WidgetTester 实例
      • 让他们成为async
    3. 然后你应该只打一次电话testWidgets(..)
      • 在此方法中,您可以调用为分发测试逻辑而设置的私有方法
      • 使用await 调用每一个,这样它们就不会同时运行

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

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

    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

    这是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()
        };
        
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-20
      • 1970-01-01
      • 2018-10-13
      相关资源
      最近更新 更多