🧪 Testgetriebene Entwicklung (TDD)
📖 Definition
TDD (Test-Driven Development) ist eine Entwicklungsmethodik, bei der Sie zuerst Tests schreiben und dann Code schreiben, um diese Tests zu bestehen. Es folgt dem Rot-Grün-Refactor-Zyklus, verbessert die Codequalität, reduziert Fehler und macht Refactoring sicherer. Unit-Tests verifizieren einzelne Funktionen oder Komponenten unabhängig.
🎯 Einfache Analogie
Bauplan Zuerst
Traditionelle Entwicklung
1. Haus bauen
2. Nach Fertigstellung prüfen
3. Probleme finden → Große Korrekturen nötig
4. Kosten steigen
TDD
1. Bauplan zeichnen (Test schreiben)
2. Nach Bauplan bauen (Code schreiben)
3. Verifizieren (Test ausführen)
4. Verbessern (Refactoring)
5. Sicher und genau
⚙️ Funktionsweise
TDD-Zyklus (Rot-Grün-Refactor)
🔴 Rot (Fehlschlag)
└─ Test schreiben → Fehlschlag (kein Code)
🟢 Grün (Erfolg)
└─ Minimalen Code schreiben → Test besteht
🔵 Refactor (Verbessern)
└─ Code verbessern → Test besteht noch
Wiederholen → Schrittweise Verbesserung
💡 Wichtige Beispiele
Grundlegendes TDD-Beispiel
// ========== 1. Rot: Test schreiben (fehlschlägt) ==========
test('add-Funktion addiert zwei Zahlen', () => {
expect(add(2, 3)).toBe(5);
});
// FAIL - add ist nicht definiert
// ========== 2. Grün: Minimaler Code (besteht) ==========
function add(a, b) {
return a + b;
}
// PASS ✅
// ========== 3. Refactor: Verbessern (falls nötig) ==========
// Code ist einfach, keine Verbesserung nötig
Unit-Test mit Jest
// user.js
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
isValidEmail() {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(this.email);
}
}
// user.test.js
describe('User', () => {
let user;
beforeEach(() => {
user = new User('Hans', 'hans@example.com');
});
test('sollte true für gültige E-Mail zurückgeben', () => {
expect(user.isValidEmail()).toBe(true);
});
test('sollte false für ungültige E-Mail zurückgeben', () => {
user.email = 'invalid-email';
expect(user.isValidEmail()).toBe(false);
});
});
Asynchrone Tests
test('async-Funktion gibt Daten zurück', async () => {
const data = await fetchData();
expect(data).toEqual({ name: 'John' });
});
Mocking
// Funktions-Mock
const mockCallback = jest.fn(x => x * 2);
[1, 2, 3].forEach(mockCallback);
expect(mockCallback).toHaveBeenCalledTimes(3);
// Modul-Mock
jest.mock('axios');
test('fetchUser gibt Benutzerdaten zurück', async () => {
axios.get.mockResolvedValue({ data: { id: 1 } });
const user = await fetchUser(1);
expect(user).toEqual({ id: 1 });
});
🤔 Häufig gestellte Fragen
F1. Vorteile von TDD?
A:
Vorteile:
1. Weniger Fehler
2. Sicheres Refactoring
3. Bessere Codequalität
4. Dokumentation
5. Vertrauen
Nachteile:
1. Anfänglicher Zeitaufwand
2. Lernkurve
3. Test-Wartung
Fazit: Langfristiger Gewinn
F2. Was Testen?
A:
// ✅ Sollte getestet werden
1. Geschäftslogik
2. Grenzfälle
3. Fehlerbehandlung
4. Öffentliche APIs
// ❌ Nicht testen müssen
1. Externe Bibliotheken
2. Einfache Getter/Setter
3. Private Implementierungsdetails
F3. Test-Abdeckungsziel?
A:
# Abdeckung messen
npm test -- --coverage
# Ziel:
80%+ Abdeckung // Realistisches Ziel
100% Abdeckung // Ideal aber unpraktisch
# Denken Sie daran:
Hohe Abdeckung ≠ Gute Tests
Aussagekräftige Tests sind wichtig!
🎬 Zusammenfassung
TDD ist die Grundlage der Softwarequalität:
- Rot-Grün-Refactor: Kern-TDD-Zyklus
- Unit-Tests: Schnell und isoliert
- Test-First: Tests treiben Design
- Kontinuierliche Verbesserung: Sicherheitsnetz für Refactoring
Tests sind eine Investition in Ihr zukünftiges Selbst! 🧪✨