Flutter Testing Standards
Priority: P0 (CRITICAL)
Core Rules
- Test Pyramid: Unit > Widget > Integration.
- Naming:
should <behavior> when <condition>. - AAA: Arrange, Act, Assert in all tests.
- Shared Mocks:
test/shared/only — no local mocks. - File Placement:
_integration_test.dartONLY inintegration_test/. - Robot-First: ALL UI assertions/interactions via Robot pattern (e.g.,
CheckoutRobot) — never rawfind.*/expect()in test body.
Widget Testing & Mocking
- Setup: Use
TestWrapper.init()insetUpAllandtester.pumpLocalizedWidget(...). - Mocking: Use GetIt registration of Mock BLoCs in
setUpAllif created internally. Use blocTest for BLoC logic and whenListen for state transitions. - Stubbing: Always stub bloc.state and bloc.stream in
setUp. Prohibitany()/anyNamed(). - Async: Use settle: false for loading or stream states to verify mid-process transitions.
Robot Pattern
- All interactions and assertions belong in
*Robot(e.g.,expectFirstOrderVisible()). - Symmetric: every
expectXxxVisible()needs expectXxxNotVisible() pairs. - BaseRobot Centralization: Extract standard scrolling (
scrollDown,scrollToEnd) and screen visibility assertions (expectScreenVisible,expectScreenNotVisible) into a commonBaseRobotor parent class to avoid duplication. - Widget tests: include a
pumpScreen(bloc:, settle:)helper. - Widget Keys: Use WidgetKeys constants from
lib/core/keys/— never inlineKey('string').
Integration Testing
- Use patrolTest with IntegrationAuthHelper.loginOrSkip($) for authenticated flows.
- Use $.native.tap() or
$.native.*for native interactions (e.g., system dialogs). - Create a robot:
final robot = OrdersRobot($.tester)— share the same class as widget tests. - Only
$.native.*and navigation helpers may remain inline in the test body.
Anti-Patterns
- No inline Key: Use
WidgetKeysconstant. Noany(): Use typed matchers. - No local mocks: Use
test/shared/. No missing bloc stub: Stubstate+stream. - No test-body logic: Move
find.*/expect()to robot. No raw find in integration tests. - No
_integration_test.dartintest/: Rename or merge. - No unused imports: Remove
v_dlswhen robots handle assertions. Check Material import needs. - No happy-path-only: Add
Edge casesgroup. No one-sided assertions: AddexpectNotVisiblepairs. - No unchecked text casing: Verify
.toUpperCase(),.tr()in source.