🧪 EasySale ERP - Test Suite¶
📋 Übersicht¶
Vollständige, skalierbare Test-Architektur für das EasySale ERP Projekt.
🏗️ Struktur¶
test/
├── unit/ # Unit Tests
│ ├── models/ # Model-Tests (Serialisierung, Logik)
│ ├── blocs/ # BLoC-Tests (State Management)
│ ├── services/ # Service-Tests (Business Logic)
│ └── helpers/ # Helper-Tests
│
├── widget/ # Widget Tests
│ ├── pages/ # Seiten-Tests
│ └── components/ # Komponenten-Tests
│
├── integration/ # Integration Tests
│ └── flows/ # End-to-End User Flows
│
├── fixtures/ # Test-Daten (JSON)
│ ├── customer.json
│ ├── article.json
│ └── fixture_reader.dart
│
├── mocks/ # Mock-Klassen
│ ├── mock_firebase.dart # Firebase Mocks
│ └── mock_services.dart # Service Mocks
│
└── helpers/ # Test-Utilities
├── test_helpers.dart # Factory-Methoden
├── firebase_test_setup.dart
├── bloc_test_helpers.dart
└── pump_app.dart # Widget Test Setup
🚀 Quick Start¶
1. Dependencies installieren¶
2. Mocks generieren (optional)¶
Falls du mockito-generierte Mocks verwenden möchtest:
3. Tests ausführen¶
Alle Tests:
Spezifische Test-Datei:
Mit Coverage:
Nur Unit Tests:
Nur Widget Tests:
📚 Test-Typen¶
Unit Tests¶
Testen isolierte Logik ohne Abhängigkeiten:
test('sollte Customer korrekt erstellen', () {
final customer = Customer(
id: 'test-id',
companyName: 'Test GmbH',
customerNumber: 'KUN-123456',
// ...
);
expect(customer.companyName, 'Test GmbH');
});
Was testen: - Models (Serialisierung, copyWith, toMap/fromMap) - Services (Business Logic, Datenverarbeitung) - BLoCs (State Management, Events) - Helper-Funktionen
Widget Tests¶
Testen UI-Komponenten:
testWidgets('sollte Kundendaten anzeigen', (tester) async {
final customer = TestHelpers.createTestCustomer();
await tester.pumpApp(CustomerCard(customer: customer));
expect(find.text(customer.companyName), findsOneWidget);
});
Was testen: - Rendering von Widgets - User-Interaktionen (Tap, Swipe, etc.) - State-Updates in UI - Navigation
Integration Tests¶
Testen komplette User-Flows:
testWidgets('sollte Kunde anlegen können', (tester) async {
// 1. App starten
// 2. Zu Kunden navigieren
// 3. "Neuer Kunde" klicken
// 4. Formular ausfüllen
// 5. Speichern
// 6. Bestätigung prüfen
});
🛠️ Test-Utilities¶
TestHelpers¶
Factory-Methoden für Test-Daten:
// Einzelner Kunde
final customer = TestHelpers.createTestCustomer(
companyName: 'Test GmbH',
customerNumber: 'KUN-123',
);
// Mehrere Kunden
final customers = TestHelpers.createTestCustomers(10);
// Einzelner Artikel
final article = TestHelpers.createTestArticle(
name: 'Test Artikel',
price: 99.99,
);
Fixtures¶
JSON-basierte Test-Daten:
import 'package:test/fixtures/fixture_reader.dart';
// Einzelnes Objekt
final customerMap = mapFixture('customer.json');
final customer = Customer.fromMap('id', customerMap);
// Liste von Objekten
final customersData = listFixture('customers.json');
Mocks¶
Mock-Services für isolierte Tests:
final mockService = MockCustomerService();
mockService.setCustomers(testCustomers);
// Normale Ausführung
final customers = await mockService.getCustomers();
// Error-Simulation
mockService.shouldFail = true;
expect(() => mockService.getCustomers(), throwsException);
Widget Test Helpers¶
Vereinfachtes Widget-Testing:
testWidgets('example', (tester) async {
// Mit vollständigem Material-App Wrapper
await tester.pumpApp(MyWidget());
// Mit Scaffold für Snackbars
await tester.pumpAppWithScaffold(MyWidget());
});
🎯 Best Practices¶
1. AAA-Pattern (Arrange, Act, Assert)¶
test('sollte Preis korrekt berechnen', () {
// Arrange - Setup
final article = Article(price: 100.0);
final quantity = 5;
// Act - Ausführen
final total = article.price * quantity;
// Assert - Überprüfen
expect(total, 500.0);
});
2. Descriptive Test Names¶
✅ Gut: sollte Customer erstellen wenn alle Pflichtfelder vorhanden
❌ Schlecht: test1
3. Unabhängige Tests¶
Jeder Test sollte isoliert laufen können:
setUp(() {
// Setup vor jedem Test
mockService = MockCustomerService();
});
tearDown(() {
// Cleanup nach jedem Test
});
4. Nutze Test-Gruppen¶
group('Customer Model', () {
group('Konstruktor', () {
test('sollte mit Pflichtfeldern erstellen', () { });
});
group('Validierung', () {
test('sollte ungültige Email ablehnen', () { });
});
});
5. Teste Edge Cases¶
test('sollte mit null-Werten umgehen', () { });
test('sollte mit leerer Liste umgehen', () { });
test('sollte bei ungültigen Daten Exception werfen', () { });
🔧 CI/CD Integration¶
GitHub Actions¶
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: subosito/flutter-action@v2
- run: flutter pub get
- run: flutter test
- run: flutter test --coverage
📊 Coverage¶
Ziel: > 80% Code Coverage
Wichtigste Bereiche: - ✅ Models: 100% - ✅ Business Logic: 90%+ - ✅ BLoCs: 80%+ - ⚠️ UI-Widgets: 60%+ (schwerer zu testen)
🐛 Debugging Tests¶
Test einzeln ausführen:¶
flutter test test/unit/models/customer/customer_model_test.dart --plain-name="sollte Customer erstellen"
Verbose Output:¶
Im VSCode:¶
- Öffne Test-Datei
- Klicke auf "Run" über dem Test
- Oder nutze "Debug" für Breakpoints
📝 Nächste Schritte¶
- Erweitere Model-Tests für alle deine Models
- BLoC-Tests für kritische Business Logic
- Service-Tests für Firebase-Integration
- Widget-Tests für wichtige UI-Komponenten
- Integration-Tests für User-Flows
📖 Weitere Ressourcen¶
💡 Tipps¶
Schnellere Tests¶
- Nutze
setUpundtearDownfür Wiederverwendung - Isoliere Firebase-Tests mit Mocks
- Parallele Ausführung mit
--concurrency=4
Wartbare Tests¶
- Nutze
TestHelpersfür konsistente Test-Daten - Zentralisiere Mock-Setup
- Dokumentiere komplexe Test-Szenarien
Debugging¶
- Nutze
printOnFailure()für Debug-Output - Verwende
debugDumpApp()in Widget-Tests - Setze Breakpoints in Debug-Modus
❓ Hilfe¶
Bei Fragen oder Problemen: 1. Schau in die Beispiel-Tests 2. Prüfe die Test-Helpers 3. Konsultiere Flutter Testing Docs
Happy Testing! 🎉