Unterschied zwischen @Mock, @MockBean und Mockito.mock ()

147

Was ist der Unterschied zwischen diesen drei Ansätzen beim Erstellen von Tests und beim Verspotten von Abhängigkeiten?

  1. @ MockBean:

    @MockBean
    MyService myservice;
  2. @Spotten:

    @Mock
    MyService myservice;
  3. Mockito.mock ()

    MyService myservice = Mockito.mock(MyService.class);
Doug
quelle

Antworten:

197

Einfache Mockito-Bibliothek

import org.mockito.Mock;
...
@Mock
MyService myservice;

und

import org.mockito.Mockito;
...
MyService myservice = Mockito.mock(MyService.class);

stammen aus der Mockito-Bibliothek und sind funktional gleichwertig.
Sie ermöglichen es, eine Klasse oder eine Schnittstelle zu verspotten und Verhaltensweisen darauf aufzuzeichnen und zu überprüfen.

Die Verwendung von Anmerkungen ist kürzer, daher vorzuziehen und häufig bevorzugt.


Beachten Sie, dass die MockitoAnnotations.initMocks(this)statische Methode aufgerufen werden muss, um Mockito-Annotationen während der Testausführung zu aktivieren .
Um Nebenwirkungen zwischen den Tests zu vermeiden, wird empfohlen, dies vor jeder Testausführung zu tun:

@Before 
public void initMocks() {
    MockitoAnnotations.initMocks(this);
}

Eine andere Möglichkeit, Mockito-Annotationen zu aktivieren, besteht darin, die Testklasse mit Annotationen zu versehen, @RunWithindem Sie angeben MockitoJUnitRunner, wer diese Aufgabe ausführt , und auch andere nützliche Dinge:

@RunWith(org.mockito.runners.MockitoJUnitRunner.class)
public MyClassTest{...}

Spring Boot-Bibliothek, die die Mockito-Bibliothek umschließt

Dies ist in der Tat eine Spring Boot-Klasse :

import org.springframework.boot.test.mock.mockito.MockBean;
...
@MockBean
MyService myservice;

Die Klasse ist in der spring-boot-testBibliothek enthalten.

Es ermöglicht das Hinzufügen von Mockito-Mocks in einem Frühling ApplicationContext.
Wenn eine Bohne, kompatibel mit der deklarierten Klasse im Kontext existiert, ersetzt es durch das Mock.
Wenn es nicht der Fall ist, es fügt die Mock im Kontext wie eine Bohne.

Javadoc Referenz:

Anmerkung, mit der einem Spring ApplicationContext Mocks hinzugefügt werden können.

...

Wenn eine vorhandene einzelne Bean desselben Typs, die im Kontext definiert ist, durch das Mock ersetzt wird, wird eine neue hinzugefügt, wenn keine vorhandene Bean definiert ist.


Bei Verwendung von klassischem / einfachem Mockito und bei Verwendung @MockBean von Spring Boot?

Unit-Tests dienen dazu, eine Komponente isoliert von anderen Komponenten zu testen, und Unit-Tests müssen ebenfalls so schnell wie möglich ausgeführt werden, da diese Tests jeden Tag ein Dutzend Mal auf den Entwicklercomputern ausgeführt werden können.

Folglich ist hier eine einfache Richtlinie:

Wenn Sie einen Test schreiben, für den keine Abhängigkeiten vom Spring Boot-Container erforderlich sind, sollten Sie dem klassischen / einfachen Mockito folgen: Er ist schnell und begünstigt die Isolierung der getesteten Komponente.
Wenn Ihr Test auf dem Spring Boot-Container basieren muss und Sie auch eine der Container-Beans hinzufügen oder verspotten möchten: @MockBeanVon Spring Boot ist der Weg.


Typische Verwendung von Spring Boot @MockBean

Während wir eine Testklasse schreiben, die mit @WebMvcTest(Web Test Slice) kommentiert ist .

Die Spring Boot-Dokumentation fasst das sehr gut zusammen:

Oft @WebMvcTestwird es auf einen einzelnen Controller beschränkt und in Kombination mit verwendet @MockBean, um Scheinimplementierungen für erforderliche Mitarbeiter bereitzustellen.

Hier ist ein Beispiel :

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private FooService fooServiceMock;

    @Test
    public void testExample() throws Exception {
         Foo mockedFoo = new Foo("one", "two");

         Mockito.when(fooServiceMock.get(1))
                .thenReturn(mockedFoo);

         mvc.perform(get("foos/1")
            .accept(MediaType.TEXT_PLAIN))
            .andExpect(status().isOk())
            .andExpect(content().string("one two"));
    }

}
davidxxx
quelle
4
Wird mit @MockBean eine Kopie der Bean erstellt und in den ApplicationContext eingefügt? Oder hat die verspottete Bohne alle ihre Methoden als null? Wenn alle Methoden null sind, kann ich sie wie mit @Mock stubben?
Doug
6
Wie erläutert, ersetzt die Verwendung @MockBeandie Bean im Anwendungskontext, wenn in Ihrer Spring-Konfiguration bereits eine Bean definiert ist, die denselben Typ deklariert. Die Injektion wird in der Klasse ausgeführt, in der Sie deklarieren. @MockBean.Die DI-Mechanismen funktionieren folgendermaßen: Sie registrieren ein Objekt im DI-Kontext und können dann das Objekt, auf das im Spring-Kontext verwiesen wird, in eine bestimmte Klasse injizieren. Sie fügen kein Objekt in den DI-Kontext ein.
Davidxxx
13

Am Ende ist es leicht zu erklären. Wenn Sie sich nur die Javadocs der Anmerkungen ansehen, werden Sie die Unterschiede sehen:

@Mock: ( org.mockito.Mock)

Markieren Sie ein Feld als Mock.

  • Ermöglicht die Erstellung von Kurzschriften.
  • Minimiert sich wiederholenden Mock-Erstellungscode.
  • Macht die Testklasse besser lesbar.
  • Erleichtert das Lesen des Überprüfungsfehlers, da der Feldname zur Identifizierung des Modells verwendet wird.

@MockBean: ( org.springframework.boot.test.mock.mockito.MockBean)

Anmerkung, mit der einem Spring ApplicationContext Mocks hinzugefügt werden können. Kann als Annotation auf Klassenebene oder für Felder in @ConfigurationKlassen oder @RunWithTestklassen verwendet werden, die SpringRunner sind.

Mocks können nach Typ oder Bean-Name registriert werden. Jede vorhandene einzelne Bean desselben Typs, die im Kontext definiert ist, wird durch das Mock ersetzt. Wenn keine vorhandene Bean definiert ist, wird eine neue hinzugefügt.

Wenn @MockBeanes in einem Feld verwendet wird und im Anwendungskontext registriert ist, wird der Mock auch in das Feld eingefügt.

Mockito.mock ()

Es ist nur die Darstellung von a @Mock.

Patrick
quelle
5
Vergessen wir nicht, dass bei @Mock der MockitoRunner oder initMocks manuell aufgerufen werden muss.
Florian Schaetz
4
Ist der einzige Unterschied zwischen @MockBeanund @Mockdass einer den Schein in Spring ApplicationContextden anderen injiziert und der andere nicht?
Doug
3
@ Doug Sie haben es gut zusammengefasst, aber man muss bedenken, dass MockBean Teil von Spring Boot
Comiventor