This repository showcases practical examples of Flutter testing concepts, aiming to empower developers to embrace Test-Driven Development (TDD) π‘. It provides hands-on examples for building a simple Flutter application with 100% test coverage using unit, widget, and integration tests.
Writing tests might seem like extra work, but it offers significant benefits:
- Confidence: Ensures your app works as expected and prevents regressions (breaking existing features) when you make changes.
- Better Design: Thinking about how to test your code often leads to more modular and maintainable designs.
- Clearer Requirements (especially when using AI): Tests act as executable specifications. Writing tests first (TDD) helps clarify requirements, which can lead to more accurate results, even when using AI code generation tools. Tests confirm the AI understood the task correctly.
- Collaboration: Tests serve as documentation for how components are supposed to behave.
This repository is designed for a wide range of Flutter developers:
- AI-assisted Coders ("Vibe Coders"): If you leverage AI for development, understanding testing basics can help you guide the AI more effectively and verify its output. Start with the basic Widget Testing examples!
- Junior Developers: New to Flutter or testing? Find simple, clear examples of unit and widget tests to get started. Look for the "Getting Started" pointers below.
- Experienced Flutter Developers (New to Testing): Comfortable with Flutter but want to add testing to your skill set? Explore practical examples for testing state management (BLoC/Cubit, Riverpod), routing, and mocking dependencies.
- Experienced Testers: Already familiar with Flutter testing? Discover different approaches, review patterns, and consider contributing your expertise!
Follow these steps to get the project running locally and execute the tests:
1. Prerequisites:
- Ensure you have
fvm
or the Flutter SDK version 3.29.x installed on your system.
2. Clone the Repository:
git clone https://github.com/Peetee06/flutter-testing-concepts.git
cd flutter-testing-concepts
3. Choose an App & Install Dependencies:
Navigate into the directory of the app implementation you'd like to explore (bloc_app
or riverpod_app
) and fetch the dependencies.
For the BLoC/Cubit version:
cd bloc_app
flutter pub get
For the Riverpod version:
cd riverpod_app
flutter pub get
4. Run Tests:
-
Unit & Widget Tests: Run all tests within the
test
directory (Make sure you are inside thebloc_app
orriverpod_app
directory):flutter test
-
Integration Tests: Run the end-to-end tests located in the
integration_test
directory. You may need a running simulator/emulator or a connected device (Make sure you are inside thebloc_app
orriverpod_app
directory).flutter test integration_test
Now you're ready to explore the code and run the various test examples!
The repository contains two implementations of the same sample application, each utilizing a different state management solution:
bloc_app/
: An implementation using the BLoC/Cubit pattern for state management π§±.riverpod_app/
: An implementation using Riverpod for state management π§.
Both applications demonstrate comprehensive testing strategies relevant to their respective state management approaches.
This section highlights specific testing scenarios demonstrated within the repository. Don't worry if some concepts seem advanced at first; start with the basics!
- Getting Started - Simple Unit Test:
- Concepts Cubit Test: See how to test basic state changes in a Cubit.
- Unit Testing (Cubits) π§©: Examples of testing business logic within Cubits, including state emissions and dependency mocking.
- Getting Started - Simple Widget Test:
- Challenge Card Test: Check if a simple widget displays the correct text.
- Widget Testing (Views/Widgets) πΌοΈ: Demonstrations of testing UI components, interactions (like button taps), and how widgets react to state changes.
- Concepts View Test (Includes testing loading states, list views, and finding specific widgets)
- Concept View Test (Includes testing widget presence based on state)
- Testing
onPressed
Callbacks (Verify button taps trigger actions)
- Routing (go_router) πΊοΈ: How to test navigation logic managed by
go_router
. Essential for multi-screen apps.- GoRouter Configuration Test
- Concept Route Test (Testing specific route presentation and interaction)
- Testing Typed Routes Navigation (Verify button tap triggers navigation)
- Mocking π: Usage of
mocktail
for creating mock ("fake") dependencies (like API clients or repositories) in tests. Crucial for isolating the code you want to test.- Mock Definitions
- (See various unit and widget tests for usage examples, e.g., Cubit tests)
- Setup and Teardown βοΈ: Examples of using
setUp
,tearDown
,setUpAll
, andtearDownAll
for setting up test conditions and cleaning up afterward.- (Visible in most
_test.dart
files, e.g., Concepts View Test)
- (Visible in most
- Integration Testing ππ: End-to-end tests covering user flows across multiple screens, simulating real user interaction. These are great for verifying critical paths in your app.
- App Integration Test
- Integration Test Specific Mocks and required build.yaml adjustments to allow code generation for mocks
- Unit Testing (Providers/Notifiers) π§©: Examples of testing Riverpod providers and notifiers, including state emissions, dependency mocking, and asynchronous operations.
- Concepts Notifier Test: Test basic asynchronous state fetching.
- Concept Notifier Test: Test a notifier dependent on parameters (
FamilyAsyncNotifier
). - Challenges Notifier Test: Test a more complex state machine using
AsyncNotifier
.
- Widget Testing (Pages/Widgets) πΌοΈ: Demonstrations of testing UI components that interact with Riverpod providers, including overriding providers for test scenarios and verifying UI based on state.
- Concepts View Test: Test list rendering, loading/error states, and navigation triggered by provider state.
- Concept View Test: Test widget rendering based on provider state and interactions within the view.
- Challenge Card Test: Test interaction within a specific widget and how it affects provider state.
- PumpApp Helper: Helper extension for wrapping widgets in
ProviderScope
andMaterialApp
for testing.
- Routing (go_router with Providers) πΊοΈ: Testing navigation managed by
go_router
where routes might depend on Riverpod providers.- Concept Route Test: Test that the correct view is rendered for a specific route and that providers are correctly overridden/accessed within the route's widget.
- Challenges Route Test: Similar example for the challenges route.
- Mocking π: Usage of
mockito
(via build_runner) for creating mock dependencies (like repositories or services) used within providers.- Mock Definitions
- Mock Generation Command (Configuration for
build_runner
) - (See various notifier and repository tests for usage examples)
- Integration Testing ππ: End-to-end tests simulating user flows through the Riverpod app, ensuring different features connected via providers and routing work together correctly.
- App Integration Test: Covers navigating from the concepts list, through concept details, to challenges, and back.
Please see the CONTRIBUTING.md file for details on how to contribute or ask questions.
You can also connect with me on LinkedIn if you have other questions or just want to chat! Always happy to help. π€