Zum Inhalt

🧪 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

flutter pub get

2. Mocks generieren (optional)

Falls du mockito-generierte Mocks verwenden möchtest:

dart run build_runner build --delete-conflicting-outputs

3. Tests ausführen

Alle Tests:

flutter test

Spezifische Test-Datei:

flutter test test/unit/models/customer/customer_model_test.dart

Mit Coverage:

flutter test --coverage
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html

Nur Unit Tests:

flutter test test/unit/

Nur Widget Tests:

flutter test test/widget/

📚 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:

flutter test --verbose

Im VSCode:

  1. Öffne Test-Datei
  2. Klicke auf "Run" über dem Test
  3. Oder nutze "Debug" für Breakpoints

📝 Nächste Schritte

  1. Erweitere Model-Tests für alle deine Models
  2. BLoC-Tests für kritische Business Logic
  3. Service-Tests für Firebase-Integration
  4. Widget-Tests für wichtige UI-Komponenten
  5. Integration-Tests für User-Flows

📖 Weitere Ressourcen

💡 Tipps

Schnellere Tests

  • Nutze setUp und tearDown für Wiederverwendung
  • Isoliere Firebase-Tests mit Mocks
  • Parallele Ausführung mit --concurrency=4

Wartbare Tests

  • Nutze TestHelpers fü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! 🎉