timetracker/.ai/testing.md
2026-08-03 21:51:48 +02:00

81 lines
2 KiB
Markdown

# 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
```