Testing Guide
Comprehensive unit and state tests for models, services, and state management.
Running Tests
# Run all tests
flutter test
# Run with verbose output
flutter test --reporter expanded
# Run specific test file
flutter test test/models/event_model_test.dart
# Run with coverage
flutter test --coverage
lcov -r coverage/lcov.info 'lib/views/*' -o coverage/filtered.info
genhtml coverage/filtered.info -o coverage/html
Test Structure
test/
โโโ core/
โ โโโ event_service_test.dart # EventService coordination tests
โ โโโ http_utils_test.dart # SSRF protection, scheme validation
โโโ models/
โ โโโ event_model_test.dart # Serialization, equality, copyWith
โ โโโ event_model_tags_test.dart # Tag handling in fromJson/toJson
โ โโโ event_model_recurrence_test.dart # Recurrence generation
โ โโโ event_tag_test.dart # Tag equality, preset validation
โ โโโ recurrence_rule_test.dart # Frequency, intervals, month clamping
โ โโโ user_model_test.dart # User serialization
โโโ state/
โโโ event_bloc_test.dart # BLoC state transitions
โโโ event_provider_test.dart # O(1) index, CRUD operations
โโโ user_provider_test.dart # User session management
Test Categories
Model Tests
Verify serialization round-trips, value equality, and domain logic:
- EventModel โ
fromJson/toJsonround-trip,copyWith(includingclearRecurrence),==andhashCode, default values - EventTag โ Case-insensitive equality, color palette bounds clamping, preset validation
- RecurrenceRule โ Occurrence generation for all frequencies, month clamping (Jan 31 + 1mo = Feb 28), end date cutoff,
summaryformatting, JSON string round-trip
// Example: RecurrenceRule month clamping test
test('monthly recurrence clamps day to valid range', () {
final rule = RecurrenceRule(
frequency: RecurrenceFrequency.monthly,
);
final start = DateTime(2026, 1, 31); // Jan 31
final dates = rule.generateOccurrences(start, maxOccurrences: 3);
expect(dates[1].day, 28); // Feb 28 (not 31!)
expect(dates[2].day, 31); // Mar 31
});
Service Tests
Verify coordination between state and persistence:
- EventService โ add/update/delete coordination, load-once guard (doesn't overwrite non-empty provider), persistence error handling (logged, not thrown)
- HttpUtils โ scheme blocking (
http,file,ftp), trusted host validation, timeout enforcement
State Tests
Verify reactive state management behavior:
- EventProvider โ O(1)
getEventById,removeEventindex rebuild,UnmodifiableListViewenforcement,notifyListenerscalls - EventBloc โ State machine transitions (
EventInitialโEventLoaded), no-op behavior in wrong state, list immutability between emissions
Coverage
Coverage is tracked via Codecov and runs automatically in CI.
Coverage Strategy
The project focuses coverage on models, services, and state โ the testable business logic. View tests (widget tests) are encouraged but not mandated, as they require more infrastructure and are harder to maintain.
Writing New Tests
Conventions
- One test file per source file, mirroring the
lib/structure - Use descriptive
group()blocks for related tests - Test edge cases: empty inputs, null fields, malformed JSON, boundary values
- Mock external dependencies (repositories, Firebase) โ don't hit real services
Example Pattern
import 'package:flutter_test/flutter_test.dart';
import 'package:everything/models/event_model.dart';
void main() {
group('EventModel', () {
test('round-trips through JSON', () {
final original = EventModel(
id: '1',
title: 'Test',
date: DateTime(2026, 1, 15),
);
final json = original.toJson();
final restored = EventModel.fromJson(json);
expect(restored, equals(original));
});
});
}