Warum Ihre Java-Tests fehlschlagen (und wie Sie das beheben)
\n\nSie haben perfekten Code geschrieben. Der Service funktioniert, die Logik ist einwandfrei und Bugs gibt es nur in fremden Projekten. Aber wenn Sie die Tests ausführen... Da ist ein Verbindungsfehler zur Datenbank, dort antwortet eine externe API nicht, und im dritten Test gibt es einen NullPointerException, weil die Konfiguration nicht richtig geladen wurde. Kommt Ihnen das bekannt vor?
\n\nDas Problem ist, dass klassische Tests von der externen Umgebung abhängen. Datenbank, REST-Dienste, Dateisystem – all das macht Tests anfällig, langsam und unberechenbar. Die Lösung sind Mock-Objekte und Fixtures. Das sind nicht nur modische Wörter, sondern Werkzeuge, die Chaos in Ordnung verwandeln.
\n\nIn diesem Artikel werden wir anhand realer Beispiele durchgehen, wie man Mock und Fixtures in Java-Tests richtig einsetzt. Sie erfahren, worin der Unterschied zwischen Stub und Mock besteht, wie man Fixtures für komplexe Szenarien konfiguriert und warum Mockito Ihr bester Freund ist. Los geht's!
\n\nMock-Objekte: Simulation ohne Schmerz
\n\nWas ist ein Mock und wozu braucht man ihn?
\n\nEin Mock-Objekt ist eine Nachbildung einer realen Komponente, die sich so verhält, wie Sie es vorgeben. Anstatt eine Datenbank hochzufahren oder eine externe API aufzurufen, erstellen Sie einen „Platzhalter", der vorab festgelegte Daten zurückgibt.
\n\nStellen Sie sich vor: Sie testen einen Service, der E-Mail-Benachrichtigungen versendet. Für einen echten Test müssten Sie einen Mail-Server hochfahren, SMTP konfigurieren, die Warteschlange prüfen... Mit einem Mock-Objekt überprüfen Sie einfach, ob der Service die Versandmethode mit den richtigen Parametern aufgerufen hat. Schnell, sauber, kontrollierbar.
\n\nMock vs Stub: Was ist der Unterschied?
\n\nAnfänger verwechseln diese Begriffe oft. Lassen Sie uns Klarheit schaffen:
\n\n- \n
- Stub – gibt festgelegte Daten zurück. Sie sagen: „Wenn die Methode getUser() aufgerufen wird, gib ein User-Objekt mit dem Namen 'John' zurück." Ein Stub prüft nicht, wie oft er aufgerufen wurde. \n
- Mock – gibt nicht nur Daten zurück, sondern prüft auch das Verhalten. Sie können sagen: „Stelle sicher, dass die Methode sendEmail() genau einmal mit einer bestimmten Adresse aufgerufen wurde." \n
Einfach ausgedrückt: Ein Stub sagt „gib mir Daten", ein Mock sagt „gib mir Daten und prüfe, wie ich verwendet werde". In der Praxis werden meist Mock-Objekte verwendet, da sie mehr Kontrolle bieten.
\n\nUnser ersten Mock mit Mockito schreiben
\n\nMockito ist die beliebteste Bibliothek für Mocks in Java. Sie ist mit JUnit 5 und Spring Boot integrierbar und die Syntax ist so einfach, dass Sie sie in fünf Minuten lernen.
\n\nAngenommen, Sie haben einen Service OrderService, der von einem Repository OrderRepository abhängt. Anstelle des echten Repositorys erstellen wir einen Mock:
import static org.mockito.Mockito.*;\nimport org.junit.jupiter.api.Test;\nimport org.mockito.Mock;\nimport org.mockito.junit.jupiter.MockitoExtension;\nimport org.junit.jupiter.api.extension.ExtendWith;\n\n@ExtendWith(MockitoExtension.class)\npublic class OrderServiceTest {\n\n @Mock\n private OrderRepository orderRepository;\n\n @Test\n void testCreateOrder() {\n // Mock-Objekt erstellen\n OrderService orderService = new OrderService(orderRepository);\n \n // Verhalten des Mocks konfigurieren\n when(orderRepository.save(any(Order.class)))\n .thenReturn(new Order(1L, "test@example.com", 100.0));\n \n // Die zu testende Methode aufrufen\n Order result = orderService.createOrder("test@example.com", 100.0);\n \n // Ergebnis überprüfen\n assertThat(result.getId()).isEqualTo(1L);\n // Überprüfen, dass die Methode save genau einmal aufgerufen wurde\n verify(orderRepository, times(1)).save(any(Order.class));\n }\n}\n\nIn diesem Beispiel haben wir:
\n- \n
- Einen Mock für
OrderRepositorymit der Annotation@Mockerstellt. \n - Konfiguriert, dass beim Aufruf von
save()eine vorab erstellte Bestellung zurückgegeben werden soll. \n - Überprü