# Testing — Conventions & Patterns ## Structure Test files mirror `lib/` under `test/`: ``` test/ features/ timer/ timer_repository_test.dart timer_notifier_test.dart entries/ entries_repository_test.dart projects/ projects_repository_test.dart reports/ reports_repository_test.dart core/ database/ app_database_test.dart ``` ## What to Test | Layer | Test type | Tool | |--------------|---------------|-------------------| | Repository | Unit | mocktail + drift in-memory | | Notifier | Unit | ProviderContainer | | Screen | Widget | flutter_test | | Navigation | Widget | GoRouter test helpers | ## Repository Tests — Pattern Use an **in-memory** Drift database: ```dart AppDatabase createTestDb() => AppDatabase(NativeDatabase.memory()); ``` Test every public DAO method: insert, update, delete, watch (stream). ## Notifier Tests — Pattern Use `ProviderContainer` with overridden repository: ```dart final container = ProviderContainer(overrides: [ projectsRepositoryProvider.overrideWithValue(MockProjectsRepository()), ]); addTearDown(container.dispose); ``` ## Widget Tests — Pattern ```dart await tester.pumpWidget( ProviderScope( overrides: [/* mock providers */], child: const MaterialApp(home: TimerScreen()), ), ); ``` - Verify key widgets are present - Tap interactions and verify state changes - Use `mocktail` `when()` / `verify()` for interactions ## Mocktail Conventions ```dart class MockTimerRepository extends Mock implements TimerRepository {} // Setup when(() => mock.getActiveEntry()).thenAnswer((_) async => null); // Verify verify(() => mock.stopTimer(any())).called(1); ``` ## Coverage Goal - Repository methods: 100% - Notifiers/providers: >80% - Widget tests: at least smoke test per screen ## Running Tests ```bash flutter test # all tests flutter test test/features/timer/ # single feature flutter test --coverage # with coverage report ```