flutter-add-widget-test

安装量: 7.2K
排名: #1159

安装

npx skills add https://github.com/flutter/skills --skill flutter-add-widget-test
Writing Flutter Widget Tests
Contents
Setup & Configuration
Core Components
Workflow: Implementing a Widget Test
Interaction & State Management
Examples
Setup & Configuration
Ensure the testing environment is properly configured before authoring widget tests.
Add the
flutter_test
dependency to the
dev_dependencies
section of
pubspec.yaml
.
Place all test files in the
test/
directory at the root of the project.
Suffix all test file names with
_test.dart
(e.g.,
widget_test.dart
).
Core Components
Utilize the following
flutter_test
components to interact with and validate the widget tree:
WidgetTester
The primary interface for building and interacting with widgets in the test environment. Provided automatically by the
testWidgets()
function.
Finder
Locates widgets in the test environment (e.g.,
find.text('Submit')
,
find.byType(TextField)
,
find.byKey(Key('submit_btn'))
).
Matcher
Verifies the presence or state of widgets located by a Finder (e.g., findsOneWidget , findsNothing , findsNWidgets(2) , matchesGoldenFile ). Workflow: Implementing a Widget Test Copy the following checklist to track progress when implementing a new widget test. Task Progress Step 1: Define the test. Use testWidgets('description', (WidgetTester tester) async { ... }) . Step 2: Build the widget. Call await tester.pumpWidget(MyWidget()) to render the UI. Wrap the widget in a MaterialApp or Directionality widget if it requires inherited directional or theme data. Step 3: Locate elements. Instantiate Finder objects for the target widgets. Step 4: Verify initial state. Use expect(finder, matcher) to validate the initial render. Step 5: Simulate interactions. Execute gestures or inputs (e.g., await tester.tap(buttonFinder) ). Step 6: Rebuild the tree. Call await tester.pump() or await tester.pumpAndSettle() to process state changes. Step 7: Verify updated state. Use expect() to validate the UI after the interaction. Step 8: Run and validate. Execute flutter test test/your_test_file_test.dart . Step 9: Feedback Loop. Review test output -> identify failing matchers -> adjust widget logic or test assertions -> re-run until passing. Interaction & State Management Apply the following conditional logic based on the type of interaction or state change being tested: If testing static rendering: Call await tester.pumpWidget() once, then immediately run expect() assertions. If testing standard state changes (e.g., button taps): Call await tester.tap(finder) . Call await tester.pump() to trigger a single frame rebuild. If testing animations, transitions, or asynchronous UI updates: Trigger the action (e.g., await tester.drag(finder, Offset(500, 0)) ). Call await tester.pumpAndSettle() to repeatedly pump frames until no more frames are scheduled (animation completes). If testing text input: Call await tester.enterText(textFieldFinder, 'Input string') . If testing items in a dynamic or long list: Call await tester.scrollUntilVisible(itemFinder, 500.0, scrollable: listFinder) to ensure the target widget is rendered before interacting with it. Examples High-Fidelity Widget Test Implementation Target Widget ( lib/todo_list.dart ): import 'package:flutter/material.dart' ; class TodoList extends StatefulWidget { const TodoList ( { super . key } ) ; @override State < TodoList

createState ( ) =

_TodoListState ( ) ; } class _TodoListState extends State < TodoList

{ final todos = < String

[ ] ; final controller = TextEditingController ( ) ; @override Widget build ( BuildContext context ) { return MaterialApp ( home : Scaffold ( body : Column ( children : [ TextField ( controller : controller ) , Expanded ( child : ListView . builder ( itemCount : todos . length , itemBuilder : ( context , index ) { final todo = todos [ index ] ; return Dismissible ( key : Key ( ' $ todo $ index ' ) , onDismissed : ( _ ) =

setState ( ( ) =

todos . removeAt ( index ) ) , child : ListTile ( title : Text ( todo ) ) , ) ; } , ) , ) , ] , ) , floatingActionButton : FloatingActionButton ( onPressed : ( ) { setState ( ( ) { todos . add ( controller . text ) ; controller . clear ( ) ; } ) ; } , child : const Icon ( Icons . add ) , ) , ) , ) ; } } Test Implementation ( test/todo_list_test.dart ): import 'package:flutter/material.dart' ; import 'package:flutter_test/flutter_test.dart' ; import 'package:my_app/todo_list.dart' ; void main ( ) { testWidgets ( 'Add and remove a todo item' , ( WidgetTester tester ) async { // 1. Build the widget await tester . pumpWidget ( const TodoList ( ) ) ; // 2. Verify initial state expect ( find . byType ( ListTile ) , findsNothing ) ; // 3. Enter text into the TextField await tester . enterText ( find . byType ( TextField ) , 'Buy groceries' ) ; // 4. Tap the add button await tester . tap ( find . byType ( FloatingActionButton ) ) ; // 5. Rebuild the widget to reflect the new state await tester . pump ( ) ; // 6. Verify the item was added expect ( find . text ( 'Buy groceries' ) , findsOneWidget ) ; // 7. Swipe the item to dismiss it await tester . drag ( find . byType ( Dismissible ) , const Offset ( 500 , 0 ) ) ; // 8. Build the widget until the dismiss animation ends await tester . pumpAndSettle ( ) ; // 9. Verify the item was removed expect ( find . text ( 'Buy groceries' ) , findsNothing ) ; } ) ; }

返回排行榜