@RunWith (MockitoJUnitRunner.class) vs MockitoAnnotations.initMocks (this)

118

Während ich einen neuen jUnit4-Test schreibe, frage ich mich, ob ich @RunWith (MockitoJUnitRunner.class) oder MockitoAnnotations.initMocks (this) verwenden soll .

Ich habe einen neuen Test erstellt und der Assistent hat automatisch einen Test mit dem Runner generiert. Javadocs für MockitoJUnitRunner geben Folgendes an:

Dieser Runner ist mit JUnit 4.4 und höher kompatibel und fügt folgendes Verhalten hinzu:

Initialisiert mit Mock kommentierte Mocks, sodass die explizite Verwendung von MockitoAnnotations.initMocks (Object) nicht erforderlich ist. Mocks werden vor jeder Testmethode initialisiert. Überprüft die Framework-Verwendung nach jeder Testmethode.

Mir ist nicht klar, ob die Verwendung des Runner einen Vorteil gegenüber der initMocks () -Methode hat, die ich in der Vergangenheit verwendet habe.

Alle Gedanken oder Links wäre dankbar!

Meerblau
quelle

Antworten:

147

MockitoJUnitRunnerbietet Ihnen eine automatische Validierung der Framework-Nutzung sowie eine automatische initMocks().

Die automatische Validierung der Framework-Nutzung lohnt sich tatsächlich. Sie können besser berichten, wenn Sie einen dieser Fehler machen.

  • Sie rufen die statische whenMethode, aber das Anstoßen mit einem passenden nicht abgeschlossen thenReturn, thenThrowoder then. (Fehler 1 im Code unten)

  • Sie rufen verifyeinen Mock auf, vergessen jedoch, den Methodenaufruf anzugeben, den Sie überprüfen möchten. (Fehler 2 im Code unten)

  • Sie rufen die whenMethode nach doReturn, doThrowoder doAnswerund einen Mock passieren, aber vergessen , die Verfahren zu schaffen , dass Sie Stummel versuchen. (Fehler 3 im Code unten)

Wenn Sie keine Validierung der Framework-Verwendung haben, werden diese Fehler erst beim folgenden Aufruf einer Mockito-Methode gemeldet . Das könnte sein

  • in der gleichen Testmethode (wie Fehler 1 unten),
  • in der nächsten Testmethode (wie Fehler 2 unten),
  • in der nächsten Testklasse.

Wenn sie im letzten Test auftreten, den Sie ausführen (wie Fehler 3 unten), werden sie überhaupt nicht gemeldet.

So könnte jeder dieser Fehlertypen aussehen. Angenommen, JUnit führt diese Tests in der hier aufgeführten Reihenfolge aus.

@Test
public void test1() {

    // ERROR 1
    // This compiles and runs, but it's an invalid use of the framework because 
    // Mockito is still waiting to find out what it should do when myMethod is called.
    // But Mockito can't report it yet, because the call to thenReturn might 
    // be yet to happen.
    when(myMock.method1());

    doSomeTestingStuff();

    // ERROR 1 is reported on the following line, even though it's not the line with
    // the error.
    verify(myMock).method2();

}

@Test
public void test2() {

    doSomeTestingStuff();

    // ERROR 2
    // This compiles and runs, but it's an invalid use of the framework because
    // Mockito doesn't know what method call to verify.  But Mockito can't report 
    // it yet, because the call to the method that's being verified might 
    // be yet to happen.
    verify(myMock);
}

@Test
public void test3() {

    // ERROR 2 is reported on the following line, even though it's not even in 
    // the same test as the error.
    doReturn("Hello").when(myMock).method1();


    // ERROR 3
    // This compiles and runs, but it's an invalid use of the framework because
    // Mockito doesn't know what method call is being stubbed.  But Mockito can't 
    // report it yet, because the call to the method that's being stubbed might 
    // be yet to happen.

    doReturn("World").when(myMock);

    doSomeTestingStuff(); 

    //  ERROR 3 is never reported, because there are no more Mockito calls. 
}

Als ich diese Antwort vor mehr als fünf Jahren zum ersten Mal schrieb, schrieb ich

Daher würde ich die Verwendung von MockitoJUnitRunnerwo immer möglich empfehlen . Wie Tomasz Nurkiewicz jedoch richtig hervorgehoben hat, können Sie es nicht verwenden, wenn Sie einen anderen JUnit-Läufer wie den Spring-Läufer benötigen.

Meine Empfehlung hat sich jetzt geändert. Das Mockito-Team hat eine neue Funktion hinzugefügt, seit ich diese Antwort zum ersten Mal geschrieben habe. Es ist eine JUnit-Regel, die genau die gleiche Funktion wie die ausführt MockitoJUnitRunner. Aber es ist besser, weil es die Verwendung anderer Läufer nicht ausschließt.

Einschließen

@Rule 
public MockitoRule rule = MockitoJUnit.rule();

in Ihrer Testklasse. Dies initialisiert die Mocks und automatisiert die Framework-Validierung. genau wie MockitoJUnitRunnertut. Jetzt können Sie aber auch SpringJUnit4ClassRunnereinen anderen JUnitRunner verwenden. Ab Mockito 2.1.0 gibt es zusätzliche Optionen, die genau steuern, welche Probleme gemeldet werden.

Dawood ibn Kareem
quelle
Ich kann definitiv nicht sagen, dass sie gleich sind. In einem Testfall schlägt das Junit-Runner-Setup für mich fehl und injiziert meine Mocks nicht richtig, es sei denn, ich mache das initMocks-Setup
dtc
Wir verwenden testng 6.8.8 + mockito 1.10.19 und natürlich können wir MockitoJUnitRunner nicht verwenden, aber das Validierungsframework funktioniert immer noch! Und es funktioniert genau wie @David Wallace. Kann jemand erklären? Liegt das daran, dass wir immer noch @ Before * -Rückrufe und MockitoAnnotations.initMocks (this) haben?
Yuranos
@ yuranos87 Klingt nach etwas, das Sie als neue Frage stellen sollten. Vergessen Sie nicht, Ihren Code anzugeben, wenn Sie dies tun - es ist ein bisschen sinnlos zu fragen, warum dieser Code XYZ ausführt, wenn Sie den Code nicht anzeigen.
Dawood ibn Kareem
1
Die Verwendung der TestRunner-Lösung übertrifft die @Rule bei weitem
Regel
1
@alexandroid Mein bester Vorschlag ist, dass Sie Ihre eigene Antwort mit schreiben @ExtendWith. Es ist nicht wirklich etwas, von dem ich weiß. Das Tolle an Stack Overflow ist, dass Sie bei einer solchen Frage mehrere richtige Antworten erhalten können.
Dawood ibn Kareem
24

Mit Runner können Sie ein wenig Codierung sparen (keine @BeforeMethode erforderlich ). Andererseits ist die Verwendung eines Läufers manchmal nicht möglich, dh wenn Sie bereits einen verwenden, wie z SpringJUnit4ClassRunner.

Das ist es. Es ist nur eine Frage der Präferenz.

Tomasz Nurkiewicz
quelle
2
Abgesehen von der Zeile initMocks () wird die Methode @Before für jedes andere Setup benötigt, oder?
OceanBlue
2
@OceanBlue: Natürlich, wenn Ihre @BeforeMethode etwas anderes enthielt, initMocks()als dass Sie es nach der Migration auf Runner beibehalten müssen.
Tomasz Nurkiewicz
Die Antwort von David Wallace zur Validierung des Frameworks beantwortet meine Frage vollständig, daher habe ich diese akzeptiert, aber +1, um darauf hinzuweisen, dass dieser Läufer nicht mit einem anderen wie dem Spring verwendet werden kann. Vielen Dank!
OceanBlue
1
Ich verwende Spring Boot und kann sagen, dass SpringJUnit4ClassRunnerMocks automatisch für mich initialisiert werden. Ich weiß jedoch nichts über einfachen Frühling.
Gustavohenke