Master Flutter Widget Testing
A Flutter widget testing expert that writes testWidgets suites with Mockito DI, navigation verification, and gesture/animation testing.
Why it matters
Ensure the quality and reliability of your Flutter applications by implementing robust widget tests. This skill provides expert guidance on best practices, advanced patterns, and effective mocking strategies for comprehensive test suites.
Outcomes
What it gets done
Implement core widget testing principles using testWidgets and pumpWidget.
Apply advanced patterns for testing StatefulWidgets, forms, and navigation.
Utilize mocking strategies with tools like Mockito for dependency injection.
Optimize tests for performance and ensure maintainability through best practices.
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/vb-flutter-test-widget | bash Overview
Flutter Widget Testing Expert
A Flutter widget testing expert that writes testWidgets suites: Mockito service mocking, form and navigation verification, gesture and animation testing, and reusable test utilities. Use it to write widget-level Flutter tests needing real rendering and interaction - taps, gestures, async loading, navigation - not pure business-logic unit tests.
What it does
Writes Flutter widget tests using testWidgets() rather than plain test(), rendering with WidgetTester.pumpWidget(), settling animations and async work with pumpAndSettle(), locating widgets via finders (find.byType(), find.text(), find.byKey()), and asserting with matchers (findsOneWidget, findsNothing). It covers concrete test patterns across a widget's lifecycle: AAA-structured basic interaction tests (verify state, act, verify new state); stateful widgets with async loading (mock a service with Mockito's when()/thenAnswer(), inject it via Provider, confirm a CircularProgressIndicator shows then disappears once data arrives); form validation (empty-submission error messages, then valid input via enterText() clearing those errors); Mockito-generated mocks via @GenerateMocks() wired through MultiProvider and organized with group()/setUp(); navigation verification using a MockNavigatorObserver to confirm didPush fired and the destination page rendered; gesture and animation testing (a swipe via tester.drag(), checking a Transform widget's mid-animation translation, then pumpAndSettle() to the final state); and performance testing of large lists (a 1000-item ListView.builder, confirming only visible items render, then tester.fling() to test scroll behavior). Reusable test utilities are factored into a TestUtils class with helpers like pumpWithProviders() for DI-wrapped setup and enterTextAndPump() for form input.
When to use - and when NOT to
Use it to write widget-level Flutter tests that need real rendering and interaction - taps, gestures, form input, async loading states, navigation, or scroll performance - rather than pure unit tests of business logic with no widget tree involved.
Inputs and outputs
Input is the Flutter widget or screen to test. Output is a testWidgets() test suite: arranged widget trees, often wrapped in MaterialApp/Provider, simulated interactions (tap(), enterText(), drag(), fling()), and assertions via finders and matchers, plus reusable setup utilities for dependency injection and common actions.
Integrations
Built on Flutter's flutter_test package (testWidgets, WidgetTester, finders, matchers), Mockito for service mocking (@GenerateMocks, when/thenAnswer), Provider/MultiProvider for dependency injection in tests, and MockNavigatorObserver for navigation verification.
Who it's for
For Flutter developers who want comprehensive, maintainable widget test suites rather than thin coverage. Ten practices apply throughout: descriptive test names, the AAA pattern, testing edge cases (empty states, errors, boundaries), mocking only external dependencies, setUp()/tearDown() for common init and cleanup, group() for organization, testing accessibility via semantic finders, avoiding assertions on implementation details in favor of user-observable behavior, being mindful of infinite animations when calling pumpAndSettle(), and testing responsive layouts by setting different screen sizes via tester.binding.window.physicalSizeTestValue.
class TestUtils {
static Future<void> pumpWithProviders(
WidgetTester tester,
Widget child, {
ApiService? apiService,
SharedPreferences? prefs,
}) async {
await tester.pumpWidget(
MaterialApp(
home: MultiProvider(
providers: [
Provider<ApiService>.value(value: apiService ?? MockApiService()),
Provider<SharedPreferences>.value(value: prefs ?? MockSharedPreferences()),
],
child: child,
),
),
);
}
static Future<void> enterTextAndPump(WidgetTester tester, Finder finder, String text) async {
await tester.enterText(finder, text);
await tester.pump();
}
}
FAQ
Common questions
Discussion
Questions & comments ยท 0
Sign In Sign in to leave a comment.