Java-Mock-Testing-Framework Mockito

Java 常用类库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:

  1. Externe Abhängigkeiten können instabil oder nicht verfügbar sein
  2. Die Testausführung wird langsamer
  3. 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:

  1. Prägnante API: Flache Lernkurve, einfacher Einstieg
  2. Leistungsstarke Funktionalität: Unterstützt die Überprüfung von Methodenaufrufen, die Konfiguration von Rückgabewerten, das Auslösen von Ausnahmen usw.
  3. Gute Lesbarkeit: Testcode ist intuitiv und leicht verständlich
  4. Aktive Community: Wird kontinuierlich aktualisiert und gepflegt, mit umfassender Dokumentation

Mockito-Kernkonzepte

1. Mock-Objekte erstellen

Beispiel

// Methode 1: Statische Methode verwenden
List mockedList = Mockito.mock(List.class);

// Methode 2: Annotationen verwenden (erfordert MockitoJUnitRunner)
@Mock
List mockedList;

2. Methodenverhalten festlegen

Beispiel

// 100 zurückgeben, wenn mockedList.size() aufgerufen wird
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

// Überprüfen, dass mockedList.add("one") einmal aufgerufen wurde
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

public class UserService {
    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

public class UserServiceTest {
    @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

// Beliebiges Integer-Argument
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 inOrder = inOrder(mockedList);

inOrder.verify(mockedList).add("first");
inOrder.verify(mockedList).add("second");

3. Partieller Mock (Spy)

Beispiel

List realList = new ArrayList();
List spyList = spy(realList);

// Echte Methode aufrufen
spyList.add("real");

// Eine bestimmte Methode mocken
doReturn(100).when(spyList).size();

Best Practices

  1. Mock nicht übermäßig einsetzen: Mocke nur notwendige Abhängigkeiten, halte Tests realistisch
  2. Interaktionen maßvoll verifizieren: Konzentriere dich auf wichtige Interaktionen, verifiziere nicht jeden Methodenaufruf
  3. Tests kurz halten: Jede Testmethode sollte nur einen funktionalen Punkt prüfen
  4. Testcode sinnvoll organisieren: @Before für gemeinsames Setup verwenden
  5. 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.


Verwandte Links

  1. Offizielle Mockito-Dokumentation
  2. Mockito GitHub-Repository

Java 常用类库Gängige Java-Klassenbibliotheken

Andere Erweiterungen