Overview
Zeus uses a comprehensive testing strategy including unit tests, widget tests, and integration tests.Unit Tests
Test business logic in isolation:Copy
import 'package:flutter_test/flutter_test.dart';
import 'package:zeus_app/cache/cache.dart';
void main() {
group('CacheManager', () {
late CacheManager cache;
setUp(() async {
cache = await CacheManager.initialize();
cache.configureSync(StubSyncApiClient());
});
tearDown(() async {
await cache.dispose();
});
test('creates wallet with correct properties', () async {
final wallet = await cache.createWallet(
name: 'Test Wallet',
currency: 'EUR',
initialBalance: 100.0,
);
expect(wallet.name, equals('Test Wallet'));
expect(wallet.currency, equals('EUR'));
expect(wallet.balance, equals(100.0));
expect(wallet.syncStatus, equals(SyncStatus.pendingCreate));
});
test('soft delete marks wallet as deleted', () async {
final wallet = await cache.createWallet(
name: 'Delete Me',
currency: 'USD',
);
await cache.wallets.delete(wallet.id);
final deleted = await cache.wallets.findById(wallet.id);
expect(deleted, isNull);
// But still exists with isDeleted = true
final allWithDeleted = await cache.wallets.findAll(includeDeleted: true);
final found = allWithDeleted.firstWhere((w) => w.id == wallet.id);
expect(found.isDeleted, isTrue);
expect(found.syncStatus, equals(SyncStatus.pendingDelete));
});
});
}
Widget Tests
Test UI components:Copy
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() {
group('WalletPage', () {
testWidgets('displays list of wallets', (tester) async {
await tester.pumpWidget(
MaterialApp(
home: BlocProvider(
create: (_) => MockWalletBloc(),
child: WalletPage(),
),
),
);
expect(find.text('Wallets'), findsOneWidget);
expect(find.byType(ListView), findsOneWidget);
});
testWidgets('shows loading indicator', (tester) async {
await tester.pumpWidget(
MaterialApp(
home: BlocProvider(
create: (_) => MockWalletBloc(),
child: WalletPage(),
),
),
);
await tester.pump(); // Initial build
expect(find.byType(CircularProgressIndicator), findsOneWidget);
});
});
}
BLoC Tests
Usebloc_test package:
Copy
import 'package:bloc_test/bloc_test.dart';
void main() {
group('WalletBloc', () {
late CacheManager cache;
setUp(() async {
cache = await CacheManager.initialize();
});
blocTest<WalletBloc, WalletState>(
'emits [Loading, Loaded] when LoadWallets is added',
build: () => WalletBloc(cache),
act: (bloc) => bloc.add(LoadWallets()),
expect: () => [
isA<WalletLoading>(),
isA<WalletLoaded>(),
],
);
blocTest<WalletBloc, WalletState>(
'emits [Loading, Error] when LoadWallets fails',
build: () => WalletBloc(cache),
act: (bloc) => bloc.add(LoadWallets()),
expect: () => [
isA<WalletLoading>(),
isA<WalletError>(),
],
);
});
}
Integration Tests
Test complete user flows:Copy
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:zeus_app/main.dart' as app;
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('End-to-end test', () {
testWidgets('create wallet and transaction', (tester) async {
app.main();
await tester.pumpAndSettle();
// Tap add wallet button
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();
// Enter wallet name
await tester.enterText(
find.byKey(Key('walletNameField')),
'Test Wallet',
);
// Save
await tester.tap(find.byKey(Key('saveButton')));
await tester.pumpAndSettle();
// Verify wallet appears
expect(find.text('Test Wallet'), findsOneWidget);
});
});
}
Running Tests
Copy
# All tests
flutter test
# Specific file
flutter test test/cache/cache_manager_test.dart
# With coverage
flutter test --coverage
# Integration tests
flutter test integration_test/
# Specific device
flutter test -d <device-id>
Best Practices
- Test behavior, not implementation - Don’t test private methods
- Use mocks - Don’t hit real APIs in unit tests
- Test edge cases - Empty lists, null values, errors
- Keep tests fast - Unit tests should run in milliseconds
- Name tests clearly -
test('should return error when network fails')

