Java-Mock-Testing-Framework Mockito
Gängige Java-Klassenbibliotheken
Was ist Mock-Testing?
In der Softwareentwicklung ist Unit-Testing ein wichtiges Mittel zur Überprüfung der Codefunktionalität. Wenn unser Code jedoch von externen Systemen (wie Datenbanken, Webdiensten usw.) abhängt, kann das direkte Testen auf mehrere Probleme stoßen:
- Externe Abhängigkeiten können instabil oder nicht verfügbar sein
- Die Testausführung wird langsamer
- Es ist schwierig, verschiedene Randbedingungen zu simulieren
Mock-Testing (Simulationstest) löst diese Probleme, indem "Stellvertreter" für Objekte erstellt werden. Mock-Objekte können:
- Das Verhalten realer Objekte simulieren
- Überprüfen, ob Interaktionen wie erwartet erfolgen
- Die tatsächliche Logik realer Objekte nicht ausführen
Warum Mockito wählen?
Mockito ist derzeit das beliebteste Mock-Testing-Framework im Java-Ökosystem und bietet die folgenden Vorteile:
- Prägnante API: Flache Lernkurve, einfacher Einstieg
- Leistungsstarke Funktionalität: Unterstützt die Überprüfung von Methodenaufrufen, die Konfiguration von Rückgabewerten, das Auslösen von Ausnahmen usw.
- Gute Lesbarkeit: Testcode ist intuitiv und leicht verständlich
- Aktive Community: Wird kontinuierlich aktualisiert und gepflegt, mit umfassender Dokumentation
Mockito-Kernkonzepte
1. Mock-Objekte erstellen
Beispiel
List mockedList = Mockito.mock(List.class);
// Methode 2: Annotationen verwenden (erfordert MockitoJUnitRunner)
@Mock
List mockedList;
2. Methodenverhalten festlegen
Beispiel
when(mockedList.size()).thenReturn(100);
// "first" zurückgeben, wenn mockedList.get(0) aufgerufen wird
when(mockedList.get(0)).thenReturn("first");
// Eine Ausnahme auslösen, wenn mockedList.get(1) aufgerufen wird
when(mockedList.get(1)).thenThrow(new RuntimeException());
3. Interaktionen überprüfen
Beispiel
verify(mockedList).add("one");
// Überprüfen Sie, dass mockedList.clear() nie aufgerufen wurde
verify(mockedList, never()).clear();
// Überprüfen Sie, dass mockedList.add("two") mindestens zweimal aufgerufen wurde
verify(mockedList, atLeast(2)).add("two");
Praktische Anwendungsbeispiele für Mockito
Testen von User Service
Angenommen, wir haben einenUserServicehängt ab vonUserRepository:
Beispiel
private UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("Benutzer nicht gefunden"));
}
}
Verwenden Sie Mockito zum Testen:
Beispiel
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testGetUserById_Success() {
// Testdaten vorbereiten
User mockUser = new User(1L, "testUser");
// Mock-Verhalten konfigurieren
when(userRepository.findById(1L))
.thenReturn(Optional.of(mockUser));
// Test ausführen
User result = userService.getUserById(1L);
// Ergebnis überprüfen
assertEquals("testUser", result.getUsername());
verify(userRepository).findById(1L);
}
@Test(expected = UserNotFoundException.class)
public void testGetUserById_NotFound() {
when(userRepository.findById(2L))
.thenReturn(Optional.empty());
userService.getUserById(2L);
}
}
Erweiterte Mockito-Funktionen
1. Argument-Matcher
Beispiel
when(mockedList.get(anyInt())).thenReturn("element");
// Argument eines bestimmten Typs
when(mockedList.contains(anyString())).thenReturn(wahr);
// Benutzerdefinierter Matcher
when(mockedList.add(argThat(arg -> arg.length() > 5))).thenReturn(wahr);
2. Überprüfen der Aufrufreihenfolge
Beispiel
inOrder.verify(mockedList).add("first");
inOrder.verify(mockedList).add("second");
3. Partieller Mock (Spy)
Beispiel
List spyList = spy(realList);
// Echte Methode aufrufen
spyList.add("real");
// Eine bestimmte Methode mocken
doReturn(100).when(spyList).size();
Best Practices
- Mock nicht übermäßig einsetzen: Mocke nur notwendige Abhängigkeiten, halte Tests realistisch
- Interaktionen maßvoll verifizieren: Konzentriere dich auf wichtige Interaktionen, verifiziere nicht jeden Methodenaufruf
- Tests kurz halten: Jede Testmethode sollte nur einen funktionalen Punkt prüfen
- Testcode sinnvoll organisieren: @Before für gemeinsames Setup verwenden
- Mit anderen Testwerkzeugen kombinieren: Zusammen mit JUnit, AssertJ usw. verwenden
Häufig gestellte Fragen (FAQ)
F: Was ist der Unterschied zwischen Mockito und PowerMock?
A: Mockito wird hauptsächlich zum Mocken gewöhnlicher Objekte verwendet, während PowerMock statische Methoden, Konstruktoren usw. mocken kann. Allerdings beeinträchtigt PowerMock die Testisolation, daher wird empfohlen, zuerst Mockito zu verwenden.
F: Wann sollte ich Spy anstelle von Mock verwenden?
A: Verwenden Sie Spy, wenn Sie überwiegend echtes Verhalten benötigen und nur wenige Methoden ändern möchten. Wenn Sie die volle Kontrolle über das Objektverhalten benötigen, verwenden Sie Mock.
F: Kann Mockito für finale Klassen oder Methoden verwendet werden?
A: Seit Mockito 2.1.0 können finale Klassen und Methoden durch Konfiguration gemockt werden, aber Sie müssen einemockito-inlineAbhängigkeit hinzufügen.