the*_*ter 3 dart flutter flutter-test flutter-animation
在编写 Flutter 小部件测试时,我遇到了一个错误,其中在 showModalBottomSheet() 期间创建的 Ticker 未被处理。
\n\n我想我明白,如果我正在实现自己的 Flutter 动画,我应该制作一个 AnimationController,并且我会AnimationController.dispose()在小部件期间调用dispose方法期间调用。
然而,由于(我相信)AnimationController 被抽象出来以提供一些便利,我不确定在哪里或如何确保测试完成后处理该小部件。
\n\n注意:代码有效,当我在模拟器/仿真器上测试时,模式底部表单很棒。我只是想能够在一个testWidgets测试中测试它。
我查看了 showModalBottomSheet 文档https://api.flutter.dev/flutter/material/showModalBottomSheet.html但仅显示了如何使用该函数。我没有找到任何方法来控制何时可以处理动画。
\n\n(额外的pump()在出现异步问题时额外提供,但似乎没有帮助)
testWidgets(\'Taping edit score button brings up bottom sheet to edit\',\n (WidgetTester tester) async {\n setUp();\n await tester.pumpWidget(MaterialApp(\n home: GameList(\n game: Game(players: players),\n ),\n ));\n await tester.tap(find.byKey(Key(\'p1-edit-score\')));\n await tester.pump();\n await tester.pump();\n expect(find.byKey(Key(\'test\')), findsOneWidget);\n await tester.tap(find.byKey(Key(\'tap-me\')));\n await tester.pump();\n await tester.pump();\n tearDown();\n });\nRun Code Online (Sandbox Code Playgroud)\n\n\nclass GameView extends StatefulWidget {\n GameView({@required this.playerList, @required this.onResetPlayerScores});\n\n final Function onResetPlayerScores;\n final List<Player> playerList;\n\n @override\n _GameState createState() => _GameState();\n}\n\nclass _GameState extends State<GameView> {\n @override\n Widget build(BuildContext context) {\n return Scaffold(\n appBar: AppBar(...),\n body: GameList(\n game: Game(players: widget.playerList),\n ),\n );\n }\n}\n\nRun Code Online (Sandbox Code Playgroud)\n\n为简洁起见,删除了一些小部件
\n\nclass GameList extends StatefulWidget {\n GameList({@required this.game});\n\n final Game game;\n\n @override\n GameListState createState() => GameListState(game: game);\n}\n\nclass GameListState extends State<GameList> {\n GameListState({@required this.game});\n\n final Game game;\n\n @override\n Widget build(BuildContext context) {\n return ListView.separated(\n shrinkWrap: true,\n itemCount: game.players.length,\n itemBuilder: (BuildContext context, int index) {\n return Card(\n child: Column(\n children: <Widget>[\n ListTile(\n trailing: Text(\n \'${game.players[index].score.toInt()}\',\n ),\n title: Text(\n \'${game.players[index].name}\',\n ),\n ),\n Row(\n children: <Widget>[\n FlatButton(\n child: Icon(\n Icons.edit,\n color: Colors.grey[700],\n ),\n onPressed: () async {\n _settingModalBottomSheet(context);\n },\n key: Key(\n \'${game.players[index].name}-edit-score\',\n ),\n ),\n ],\n ),\n ],\n ),\n );\n },\n separatorBuilder: (BuildContext context, int index) => const Divider(),\n );\n }\n}\n\nvoid _settingModalBottomSheet(context) {\n showModalBottomSheet(\n context: context,\n builder: (BuildContext buildContext) {\n return Center(\n child: Container(\n child: Wrap(\n children: <Widget>[\n Text(\n \'edit\',\n key: Key(\'test\'),\n ),\n ListTile(\n leading: Icon(Icons.edit),\n title: Text(\'Video\'),\n onTap: () {\n Navigator.pop(context, \'video\');\n },\n key: Key(\'tap-me\'),\n ),\n ],\n ),\n ),\n );\n },\n );\n}\nRun Code Online (Sandbox Code Playgroud)\n\nflutter test。我认为最重要的部分。OverlayState created a Ticker via its TickerProviderStateMixin, but at the time dispose() was called\non the mixin, that Ticker was still active. All Tickers must be disposed before calling\nsuper.dispose(). Tickers used by AnimationControllers should be disposed by calling dispose() on the\nAnimationController itself. Otherwise, the ticker will leak.\nRun Code Online (Sandbox Code Playgroud)\n\nflutter testThe following assertion was thrown while finalizing the widget tree:\nOverlayState#bfe06(tickers: tracking 1 ticker, entries: [OverlayEntry#c26ee(opaque: false;\nmaintainState: false), OverlayEntry#7cd4f(opaque: false; maintainState: true),\nOverlayEntry#d496e(opaque: false; maintainState: false), OverlayEntry#e9ad3(opaque: false;\nmaintainState: true)]) was disposed with an active Ticker.\nOverlayState created a Ticker via its TickerProviderStateMixin, but at the time dispose() was called\non the mixin, that Ticker was still active. All Tickers must be disposed before calling\nsuper.dispose(). Tickers used by AnimationControllers should be disposed by calling dispose() on the\nAnimationController itself. Otherwise, the ticker will leak.\nThe offending ticker was: _WidgetTicker(created by OverlayState#bfe06(tickers: tracking 0 tickers,\nentries: [OverlayEntry#c26ee(opaque: false; maintainState: false), OverlayEntry#7cd4f(opaque: false;\nmaintainState: true)]))\nThe stack trace when the _WidgetTicker was actually created was:\n#0 new Ticker.<anonymous closure> (package:flutter/src/scheduler/ticker.dart:64:40)\n#1 new Ticker (package:flutter/src/scheduler/ticker.dart:66:6)\n#2 new _WidgetTicker (package:flutter/src/widgets/ticker_provider.dart:225:80)\n#3 _OverlayState&State&TickerProviderStateMixin.createTicker\n(package:flutter/src/widgets/ticker_provider.dart:161:34)\n#4 new AnimationController (package:flutter/src/animation/animation_controller.dart:245:21)\n#5 BottomSheet.createAnimationController\n(package:flutter/src/material/bottom_sheet.dart:128:12)\n#6 _ModalBottomSheetRoute.createAnimationController\n(package:flutter/src/material/bottom_sheet.dart:356:40)\n#7 TransitionRoute.install (package:flutter/src/widgets/routes.dart:176:19)\n#8 ModalRoute.install (package:flutter/src/widgets/routes.dart:907:11)\n#9 NavigatorState.push (package:flutter/src/widgets/navigator.dart:1754:11)\n#10 Navigator.push (package:flutter/src/widgets/navigator.dart:1093:34)\n#11 showModalBottomSheet (package:flutter/src/material/bottom_sheet.dart:427:20)\n#12 _settingModalBottomSheet (package:score_keeper/game_list.dart:98:3)\n#13 GameListState.build.<anonymous closure>.<anonymous closure>\n(package:score_keeper/game_list.dart:65:23)\n<asynchronous suspension>\n#14 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:635:14)\n#15 _InkResponseState.build.<anonymous closure>\n(package:flutter/src/material/ink_well.dart:711:32)\n#16 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)\n#17 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:365:11)\n#18 TapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:312:7)\n#19 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27)\n#20\n_TestWidgetsFlutterBinding&BindingBase&ServicesBinding&SchedulerBinding&GestureBinding.handleEvent\n(package:flutter/src/gestures/binding.dart:222:20)\n#21\n_TestWidgetsFlutterBinding&BindingBase&ServicesBinding&SchedulerBinding&GestureBinding.dispatchEvent\n(package:flutter/src/gestures/binding.dart:198:22)\n#22 TestWidgetsFlutterBinding.dispatchEvent (package:flutter_test/src/binding.dart:365:11)\n#23 WidgetTester.sendEventToBinding.<anonymous closure>\n(package:flutter_test/src/widget_tester.dart:458:15)\n#25 WidgetTester.sendEventToBinding.<anonymous closure>\n(package:flutter_test/src/widget_tester.dart:457:39)\n#28 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:69:41)\n#29 WidgetTester.sendEventToBinding (package:flutter_test/src/widget_tester.dart:457:27)\n#30 TestGesture.up.<anonymous closure> (package:flutter_test/src/test_pointer.dart:422:13)\n#32 TestGesture.up.<anonymous closure> (package:flutter_test/src/test_pointer.dart:420:39)\n#35 TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:69:41)\n#36 TestGesture.up (package:flutter_test/src/test_pointer.dart:420:27)\n#37 WidgetController.tapAt.<anonymous closure> (package:flutter_test/src/controller.dart:263:21)\n#51 WidgetController.startGesture (package:flutter_test/src/controller.dart)\n#75 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure>\n(package:flutter_test/src/binding.dart:1026:17)\n#77 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure>\n(package:flutter_test/src/binding.dart:1014:35)\n(elided 58 frames from class _FakeAsync, package dart:async, package dart:async-patch, and package\nstack_trace)\n\n\nWhen the exception was thrown, this was the stack:\n#0 _OverlayState&State&TickerProviderStateMixin.dispose.<anonymous closure> (package:flutter/src/widgets/ticker_provider.dart:178:13)\n#1 _OverlayState&State&TickerProviderStateMixin.dispose (package:flutter/src/widgets/ticker_provider.dart:191:6)\n#2 StatefulElement.unmount (package:flutter/src/widgets/framework.dart:4107:12)\n#3 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1737:13)\n#4 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#5 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#6 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#7 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#8 SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:5080:14)\n#9 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#10 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#11 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#12 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#13 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#14 SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:5080:14)\n#15 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#16 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#17 SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:5080:14)\n#18 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#19 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#20 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#21 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#22 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#23 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#24 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#25 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#26 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#27 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#28 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#29 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#30 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#31 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#32 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#33 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#34 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#35 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#36 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#37 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#38 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#39 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#40 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#41 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#42 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#43 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#44 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#45 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#46 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#47 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#48 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#49 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#50 SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:5080:14)\n#51 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#52 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#53 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#54 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#55 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#56 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#57 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#58 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#59 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#60 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#61 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#62 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#63 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#64 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#65 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#66 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#67 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#68 SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:5080:14)\n#69 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#70 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#71 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#72 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#73 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#74 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#75 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#76 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#77 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#78 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#79 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#80 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#81 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#82 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#83 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#84 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#85 _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:1735:7)\n#86 ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:3955:14)\n#87 _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:1733:13)\n#88 ListIterable.forEach (dart:_internal/iterable.dart:39:13)\n#89 _InactiveElements._unmountAll (package:flutter/src/widgets/framework.dart:1746:25)\n#90 BuildOwner.finalizeTree.<anonymous closure> (package:flutter/src/widgets/framework.dart:2426:27)\n#91 BuildOwner.lockState (package:flutter/src/widgets/framework.dart:2258:15)\n#92 BuildOwner.finalizeTree (package:flutter/src/widgets/framework.dart:2425:7)\n#93 AutomatedTestWidgetsFlutterBinding.drawFrame (package:flutter_test/src/binding.dart:953:18)\n#94 _TestWidgetsFlutterBinding&BindingBase&ServicesBinding&SchedulerBinding&GestureBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:285:5)\n#95 _TestWidgetsFlutterBinding&BindingBase&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1016:15)\n#96 _TestWidgetsFlutterBinding&BindingBase&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:958:9)\n#97 AutomatedTestWidgetsFlutterBinding.scheduleWarmUpFrame (package:flutter_test/src/binding.dart:915:5)\n#98 runApp (package:flutter/src/widgets/binding.dart:787:7)\n#99 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:637:7)\n<asynchronous suspension>\n#102 TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:613:14)\n#103 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1010:24)\n#109
我在测试时也有类似的行为。修改后解决
await tester.pump();
Run Code Online (Sandbox Code Playgroud)
为了
await tester.pumpAndSettle();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4491 次 |
| 最近记录: |