如何在 Flutter 中为多个测试“设置"一个“WidgetTester" [英] How to `setUp` a `WidgetTester` for Multiple Tests in Flutter
问题描述
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.
总结一下:
- 在
main()
中创建 - 从该结构内部为您想要的每组测试创建您自己的私有方法.对于这些私有方法中的每一个:
- 传入
WidgetTester
实例 - 让它们
异步
- 传入
group(..)
结构- Create the
group(..)
structure insidemain()
- 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
- Pass in the
- 在这个方法中,你可以调用你设置的私有方法来分发测试逻辑
- 用
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屋!