{}const=>[]async()letfn</>var
Entwicklung

Unit-Tests: Code automatisch prüfen

Erfahren Sie, wie Unit-Tests helfen, Code automatisch zu überprüfen, Fehler zu vermeiden und Zeit beim Debuggen zu sparen. Praktische Beispiele in JavaScript, Prinzipien zum Schreiben von Tests, AAA-Muster und Tipps zum Implementieren von Tests in der Entwicklung.

К

Kodik

Autor

6 Min. Lesezeit

Stellen Sie sich vor, Sie haben eine komplexe Funktion zur Berechnung von Rabatten in einem Online-Shop entwickelt. Der Code funktioniert einwandfrei, aber nach einem Monat nimmt ein Kollege kleine Änderungen an einem anderen Teil der Anwendung vor - und plötzlich beginnen Ihre Berechnungen, falsche Ergebnisse zu liefern. Wie kann man ein solches Problem rechtzeitig erkennen? Die Antwort ist einfach: Unit-Tests.

Was sind Unit-Tests?

Unit-Tests sind automatische Tests kleiner Codebereiche, in der Regel einzelner Funktionen oder Methoden. Sie funktionieren wie Kontrollpunkte, die ständig überprüfen, ob sich Ihr Code genau so verhält, wie es beabsichtigt ist.

Die Grundidee ist einfach: Sie schreiben Code, der Ihre Funktion mit bekannten Eingabedaten aufruft und prüft, ob das Ergebnis den Erwartungen entspricht. Wenn das Ergebnis korrekt ist, wird der Test bestanden, wenn nicht, fällt der Test aus und meldet einen Fehler.

🔥 100.000+ Schüler sind bereits bei uns

Genug Theorie gelesen?
Zeit zu coden!

Kodik — eine App, in der du durch Praxis programmieren lernst. KI-Mentor, interaktive Lektionen, echte Projekte.

🤖 KI 24/7
🎓 Zertifikate
💰 Kostenlos
🚀 Jetzt starten
Heute beigetreten

Warum Unit-Tests benötigt werden

Anfänger fragen sich oft: Warum sollte man Zeit damit verbringen, Tests zu schreiben, wenn man den Code einfach manuell überprüfen kann? Es gibt mehrere Gründe.

Der erste Grund ist das Vertrauen in das Refactoring. Wenn Sie eine Testabdeckung haben, können Sie den Code sicher verbessern, da Sie wissen, dass die Tests sofort melden, wenn etwas kaputt geht. Es ist wie ein Sicherheitsnetz für einen Akrobaten.

Der zweite Grund ist die Dokumentation. Gut geschriebene Tests zeigen, wie eine Funktion verwendet werden sollte, welche Eingabedaten sie akzeptiert und was sie zurückgibt. Dies ist eine lebende Dokumentation, die immer auf dem neuesten Stand ist.

Der dritte Grund ist die langfristige Zeitersparnis. Ja, das Schreiben von Tests nimmt jetzt Zeit in Anspruch, spart aber in Zukunft Stunden beim Debuggen. Automatische Tests werden in Sekundenschnelle ausgeführt und überprüfen alle Funktionen, während manuelle Tests Stunden dauern können.

Ein einfaches Beispiel

Schauen wir uns ein praktisches Beispiel in JavaScript an. Angenommen, wir haben eine Funktion zum Validieren von E-Mail-Adressen:

function isValidEmail(email) {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

Schreiben wir nun einen Unit-Test für sie mit dem beliebten Jest-Framework:

describe('isValidEmail', () => {
  test('must return true for a valid email', () => {
    expect(isValidEmail('user@example.com')).toBe(true);
  });

  test('must return false for email without @', () => {
    expect(isValidEmail('userexample.com')).toBe(false);
  });

  test('must return false for email without domain', () => {
    expect(isValidEmail('user@')).toBe(false);
  });

  test('must return false for an empty string', () => {
    expect(isValidEmail('')).toBe(false);
  });
});

Jeder Test prüft ein bestimmtes Szenario. Wenn jemand den regulären Ausdruck ändert und versehentlich die Validierung unterbricht, werden die Tests dies sofort erkennen.

Grundsätze für das Schreiben guter Tests

Ein guter Unit-Test sollte unabhängig sein. Dies bedeutet, dass er nicht von den Ergebnissen anderer Tests oder der Reihenfolge abhängen sollte, in der sie durchgeführt werden. Jeder Test erstellt seine eigenen Daten und überprüft nur eine bestimmte Sache.

Tests sollten schnell sein. Wenn es Minuten dauert, alle Tests auszuführen, werden Entwickler sie seltener ausführen. Unit-Tests sollten in Millisekunden ausgeführt werden, damit sie nach jeder Codeänderung ausgeführt werden können.

Tests sollten klar sein. Wenn ein Test fehlschlägt, sollten Sie sofort verstehen, was genau kaputt ist. Verwenden Sie beschreibende Testnamen und eindeutige Fehlermeldungen.

AAA-Muster

Ein beliebter Ansatz zum Strukturieren von Tests ist das AAA-Muster: Arrange, Act, Assert (Vorbereiten, Handeln, Überprüfen).

test('must correctly calculate the 10% discount', () => {
  // Arrange - Datenaufbereitung
  const price = 1000;
  const discount = 10;
  
  // Act - Ausführen einer Aktion
  const result = calculateDiscount(price, discount);
  
  // Assert — Ergebnisprüfung
  expect(result).toBe(900);
});

Diese Struktur macht Tests auch für diejenigen lesbar und verständlich, die den Code zum ersten Mal sehen.

Testen von Grenzfällen

Eine der wichtigsten Aufgaben von Unit-Tests ist die Überprüfung von Grenzfällen. Dies sind Situationen, die am Rande akzeptabler Werte liegen: leere Arrays, Nullwerte, maximale Zahlen, Sonderzeichen.

describe('calculateAge', () => {
  test('must return 0 for a newborn', () => {
    const today = new Date();
    expect(calculateAge(today)).toBe(0);
  });

  test('must process a leap year', () => {
    const birthDate = new Date('2000-02-29');
    expect(calculateAge(birthDate)).toBeGreaterThan(0);
  });

  test('should throw an error for a date in the future', () => {
    const futureDate = new Date('2030-01-01');
    expect(() => calculateAge(futureDate)).toThrow();
  });
});

Gerade Grenzfälle werden am häufigsten zur Fehlerquelle in der Produktion.

Mockups und Stubs

Oft hängt die Funktion von externen Diensten ab: Datenbanken, APIs, Dateisystem. Für Unit-Tests wollen wir keine echten externen Ressourcen nutzen – das ist langsam und unzuverlässig. Stattdessen werden Mocks und Stubs verwendet.

// Die Funktion, die wir testen
async function getUserData(userId) {
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
}

// Test mit Mock
test('must receive user data', async () => {
  // Wir erstellen ein Mockup für Fetch
  global.fetch = jest.fn(() =>
    Promise.resolve({
      json: () => Promise.resolve({ id: 1, name: 'Alexey' })
    })
  );

  const userData = await getUserData(1);
  
  expect(userData.name).toBe('Alexey');
  expect(fetch).toHaveBeenCalledWith('/api/users/1');
});

Mit Mocks können Sie den zu testenden Code isolieren und überprüfen, ob die Funktion korrekt mit externen Abhängigkeiten interagiert.

Code-Abdeckung durch Tests

Die Code-Abdeckung (Code Coverage) gibt an, wie viel Prozent Ihres Codes während der Tests ausgeführt werden. Die meisten Testwerkzeuge können Berichte über die Code-Abdeckung erstellen.

Es ist jedoch wichtig zu verstehen, dass eine 100% ige Abdeckung keine Fehlerfreiheit garantiert. Die Abdeckung zeigt an, dass der Code ausgeführt wurde, garantiert jedoch nicht, dass er auf alle möglichen Szenarien getestet wurde. Streben Sie nach einer angemessenen Abdeckung kritischer Teile des Codes.

Tests in verschiedenen Sprachen

Das Konzept der Unit-Tests ist universell, aber die Tools unterscheiden sich je nach Programmiersprache.

Die Frameworks pytest und unittest sind in Python beliebt. Sie bieten eine einfache Syntax zum Schreiben von Tests und viele integrierte Dienstprogramme zum Testen.

Jest, Mocha, Jasmine werden in JavaScript und TypeScript verwendet. Jest ist besonders beliebt wegen seiner integrierten Unterstützung für Mocks und seiner benutzerfreundlichen API.

In Vue.js-Anwendungen wird Vue Test Utils häufig in Verbindung mit Jest verwendet, wodurch Komponenten isoliert getestet, ihre Darstellung und Interaktion mit dem Benutzer überprüft werden können.

Java verwendet traditionell JUnit und PHP verwendet PHPUnit. Jedes dieser Tools ist an die Besonderheiten seiner Sprache angepasst, aber die Grundprinzipien bleiben gleich.

TDD: Entwicklung durch Testen

Einige Teams praktizieren TDD (Test-Driven Development), ein Ansatz, bei dem Tests geschrieben werden, bevor der Hauptcode geschrieben wird. Der Prozess sieht so aus: Zuerst schreiben Sie einen Falling-Test, der das gewünschte Verhalten beschreibt, dann schreiben Sie den Mindestcode, damit der Test bestanden wird, und schließlich refaktorieren Sie den Code, wobei die Tests grün bleiben.

Dieser Ansatz hilft, die Architektur besser zu durchdenken und stellt sicher, dass der gesamte Code von Tests abgedeckt wird. TDD erfordert jedoch Disziplin und ist nicht immer für experimentelle Projekte geeignet.

Wann Unit-Tests nicht benötigt werden

Um ehrlich zu sein, nicht jeder Code benötigt Unit-Tests. Einfache Getter und Setter, triviale Formatierungsfunktionen, UI-Komponenten ohne Logik - all dies kann ohne Tests auskommen oder durch Integrationstests abgedeckt werden.

Konzentrieren Sie sich auf das Testen von Geschäftslogik, komplexen Algorithmen, Funktionen mit bedingter Logik und Code, der für die Anwendung von entscheidender Bedeutung ist. Hier werden die Tests den größten Nutzen bringen.

Möchten Sie mehr über Tests und andere professionelle Entwicklungspraktiken erfahren?

Anlage Kodik bietet interaktive Kurse in Python, JavaScript und vielen anderen Technologien. Die Schulung ist von einfach bis komplex aufgebaut und beinhaltet praktische Aufgaben und reale Beispiele.

Schließen Sie sich unserem Telegram-Kanal, wo Sie eine aktive Entwicklergemeinschaft finden, die bereit ist, bei Fragen zu helfen, Erfahrungen auszutauschen und Sie auf Ihrem Weg zum Erlernen der Programmierung zu unterstützen!

🎯Hör auf zu zögern

Artikel gefallen?
Zeit zum Üben!

Bei Kodik liest du nicht nur — du schreibst sofort Code. Theorie + Praxis = echte Skills.

Sofortige Praxis
🧠KI erklärt Code
🏆Zertifikat

Keine Registrierung • Keine Karte