So beheben Sie eine unnötige Stubbing-Ausnahme

100

Mein Code ist wie folgt:

@RunWith(MockitoJUnitRunner.class)
public class MyClass {

    private static final String code ="Test";

    @Mock
     private MyClassDAO dao;

    @InjectMocks
     private MyClassService Service = new MyClassServiceImpl();

    @Test
     public void testDoSearch() throws Exception {
         final String METHOD_NAME = logger.getName().concat(".testDoSearchEcRcfInspections()");
         CriteriaDTO dto = new CriteriaDTO();
         dto.setCode(code);
         inspectionService.searchEcRcfInspections(dto);
         List<SearchCriteriaDTO> summaryList = new ArrayList<SearchCriteriaDTO>();
         inspectionsSummaryList.add(dto);
         when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
         verify(dao).doSearchInspections(dto);

      }
}

Ich komme unter die Ausnahme

org.mockito.exceptions.misusing.UnnecessaryStubbingException: 
Unnecessary stubbings detected in test class: Test
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at service.Test.testDoSearch(Test.java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.
  at org.mockito.internal.exceptions.Reporter.formatUnncessaryStubbingException(Reporter.java:838)
  at org.mockito.internal.junit.UnnecessaryStubbingsReporter.validateUnusedStubs(UnnecessaryStubbingsReporter.java:34)
  at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:49)
  at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:103)
  at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
  at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Bitte helfen Sie mir bei der Lösung

VHS
quelle

Antworten:

121

Ersetzen @RunWith(MockitoJUnitRunner.class)durch @RunWith(MockitoJUnitRunner.Silent.class).

Sumit
quelle
44
Herzlich willkommen. Es lohnt sich, Ihre Antwort zu aktualisieren, um zu erklären, warum sie diesen Code durch OP ersetzen sollten. Dies wird ihnen und zukünftigen Besuchern helfen, zu verstehen.
Bugs
5
Übrigens ist es @RunWith(MockitoJUnitRunner.Silent.class)und nicht still
Fgysin stellt Monica am
6
In Kotlin:@RunWith(MockitoJUnitRunner.Silent::class)
Juan Saravia
9
Ich bin mir nicht sicher, warum diese Antwort ohne Erklärung immer wieder positiv bewertet wird. Andere Antworten sind aussagekräftiger und genauer.
Yogesh
8
Dies löst das Problem nicht, sondern unterdrückt einfach die Fehlermeldung und wirkt sich auch auf alle anderen Tests (falls vorhanden) in der Klasse aus.
Fechter
99

Zuerst sollten Sie Ihre Testlogik überprüfen. Normalerweise gibt es 3 Fälle. Erstens verspotten Sie eine falsche Methode (Sie haben einen Tippfehler gemacht oder jemand hat den getesteten Code geändert, sodass die verspottete Methode nicht mehr verwendet wird). Zweitens schlägt Ihr Test fehl, bevor diese Methode aufgerufen wird. Drittens ist Ihre Logik falsch, wenn / switch irgendwo im Code verzweigt, so dass die verspottete Methode nicht aufgerufen wird.

Wenn dies der erste Fall ist, möchten Sie immer die verspottete Methode für die im Code verwendete ändern. Beim zweiten und dritten kommt es darauf an. Normalerweise sollten Sie dieses Modell einfach löschen, wenn es keine Verwendung hat. Manchmal gibt es jedoch bestimmte Fälle bei parametrisierten Tests, die diesen anderen Weg einschlagen oder früher fehlschlagen sollten. Dann können Sie diesen Test in zwei oder mehr separate Tests aufteilen, aber das sieht nicht immer gut aus. 3 Testmethoden mit möglicherweise 3 Argumenten, mit denen Anbieter testen können, lassen Sie unlesbar aussehen. In diesem Fall können Sie diese Ausnahme für JUnit 4 entweder stumm schalten

@RunWith(MockitoJUnitRunner.Silent.class) 

Anmerkung oder wenn Sie den Regelansatz verwenden

@Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.LENIENT);

oder (das gleiche Verhalten)

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

Für JUnit 5-Tests können Sie diese Ausnahme mithilfe der im mockito-junit-jupiterPaket enthaltenen Anmerkungen stumm schalten.

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class JUnit5MockitoTest {
}
Dcortez
quelle
3
@MockitoSettings (strictness = Strictness.LENIENT) ist der einfachste Weg, um die Strenge in meinem Setup anzupassen. Vielen Dank!
Matt
4
Diese Antwort bietet einen guten Überblick über die Möglichkeiten. Sie können die milde Strenge jedoch auch von Fall zu Fall festlegen, indem Sie Mockito.lenient().when(...)Folgendes verwenden: für diese spezielle Frage wäre esMockito.lenient().when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);
neXus
Definieren Sie ExtendWith in Oberklassen und MockitoSettings in Unterklassen, wenn Sie sich mit Testhierarchien befassen. Hoffe, das spart Zeit für jemanden auf meine Kosten.
miracle_the_V
31

Lautlos ist keine Lösung. Sie müssen Ihr Modell in Ihrem Test reparieren. Siehe offizielle Dokumentation hier .

Unnötige Stubs sind gestubbte Methodenaufrufe, die während der Testausführung nie realisiert wurden (siehe auch MockitoHint). Beispiel:

//code under test:
 ...
 String result = translator.translate("one")
 ...

 //test:
 ...
 when(translator.translate("one")).thenReturn("jeden"); // <- stubbing realized during code execution
 when(translator.translate("two")).thenReturn("dwa"); // <- stubbing never realized
 ...

Beachten Sie, dass eine der Stubbed-Methoden während der Testausführung im zu testenden Code nie realisiert wurde. Das Streu-Stubbing kann ein Versehen des Entwicklers, das Artefakt des Kopierens und Einfügens oder der Effekt sein, der den Test / Code nicht versteht. In beiden Fällen erhält der Entwickler unnötigen Testcode. Um die Codebasis sauber und wartbar zu halten, muss unnötiger Code entfernt werden. Ansonsten sind Tests schwerer zu lesen und zu begründen.

Weitere Informationen zum Erkennen nicht verwendeter Stichleitungen finden Sie unter MockitoHint.

Stéphane GRILLON
quelle
13
Es gibt viele Situationen, in denen Sie 8-9 Tests für ein ähnliches @ BeforeEach-Setup schreiben, in denen das von einem Stub zurückgegebene Element aufgrund der Geschäftslogik bei einer Handvoll Tests nicht verwendet wird. Sie können entweder (A) es in mehrere Tests aufteilen und den Abschnitt \ @BeforeEach abzüglich des einen Elements effektiv kopieren / einfügen. (B) Kopieren Sie die einzelne Zeile, über die Mockito emo ist, in die 6 Tests, die sie verwenden, und führen Sie sie aus nicht in den 2, die nicht oder (C) Verwenden Sie lautlos. Ich bevorzuge Silent / Warning. Es ist kein gebrochener Test.
RockMeetHardplace
1
@RockMeetHardplace, Silent ist keine Lösung . Sie sehen schnell weniger Kopieren / Einfügen. Wenn Sie jedoch Ihre Tests durch neue Personen in Ihrem Projekt verwalten, ist dies problematisch. Wenn die Mockito-Buchhandlung das tut, ist das nicht umsonst.
Stéphane GRILLON
2
@sgrillon: Aber dieses System erkennt viele falsch-positive Ergebnisse. Das heißt, es heißt, dass etwas nicht verwendet wird, aber dies ist eindeutig nicht der Fall, da das Entfernen des Stubs die Ausführung unterbricht. Es ist nicht so, dass der Testcode nicht verbessert werden kann, es ist so, dass eine wichtige Stubbing-Linie niemals als "unnötig" erkannt werden sollte . Daher ist es zu eifrig, diese Prüfung deaktivieren zu können.
Carighan
@Carighan, wenn Ihr Mock als falsch erkannt wird, ist es möglicherweise nicht das, was Sie denken. Dies gibt Ihnen einen OK-Test, während möglicherweise ein Fehler vorliegt.
Stéphane GRILLON
@sgrillon, tut mir leid, dass ich darauf nie zurückgekommen bin. Es stellte sich heraus, dass es früher einen Fehler gab, bei dem abhängig von der Reihenfolge der Testausführung "falsche Treffer" generiert wurden, bei denen Stubs, die in einem Test verwendet, aber in einem anderen überschrieben wurden, diesen auslösten. Es ist jedoch lange behoben, soweit ich das beurteilen kann.
Carighan
27

Für mich weder das @Rulenoch das@RunWith(MockitoJUnitRunner.Silent.class) Vorschläge funktioniert. Es war ein Legacy-Projekt, bei dem wir ein Upgrade auf Mockito-Core 2.23.0 durchgeführt haben.

Wir könnten das loswerden, UnnecessaryStubbingExceptionindem wir :

Mockito.lenient().when(mockedService.getUserById(any())).thenReturn(new User());

anstatt:

when(mockedService.getUserById(any())).thenReturn(new User());

Unnötig zu erwähnen, dass Sie sich lieber den Testcode ansehen sollten, aber wir mussten zuerst das Zeug kompilieren und die Tests ausführen;)

philonous
quelle
6
MEINER BESCHEIDENEN MEINUNG NACH. Dies ist die nützlichste Antwort, die ich hier gefunden habe, als ich die gesamte Testklasse zum Schweigen gebracht habe.
Priyeshdiukar
Da ich nur 1 Spott unterdrücken wollte, ist dies die beste Antwort für mich. Keine wirkliche Antwort für das OP.
Hans Wouters
25
 when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
 verify(dao).doSearchInspections(dto);

Das whenhier konfiguriert Ihren Mock, um etwas zu tun. Sie verwenden dieses Modell jedoch nach dieser Zeile in keiner Weise mehr (abgesehen von a verify). Mockito warnt Sie, dass die whenLinie daher sinnlos ist. Vielleicht haben Sie einen logischen Fehler gemacht?

john16384
quelle
Vielen Dank für Ihre Hilfe
VHS
Ich brauche sowohl wann als auch überprüfe Aussagen, die freundlicherweise vorschlagen, wie man weiter geht
VHS
2
Rufen Sie eine Funktion in Ihrer Testklasse ( Service) auf, um festzustellen, ob sie richtig reagiert. Das hast du überhaupt nicht gemacht, also was testest du hier?
John16384
3

Wenn Sie sich einen Teil Ihrer Stapelspur ansehen, sieht es so aus, als würden Sie die dao.doSearch()Stelle anderswo stubben . Eher wie das wiederholte Erstellen der Stubs derselben Methode.

Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at service.Test.testDoSearch(Test.java:72)
Please remove unnecessary stubbings or use 'silent' option. More info: javadoc for UnnecessaryStubbingException class.

Betrachten Sie zum Beispiel die folgende Testklasse:

@RunWith(MockitoJUnitRunner.class)
public class SomeTest {
    @Mock
    Service1 svc1Mock1;

    @Mock
    Service2 svc2Mock2;

    @InjectMock
    TestClass class;

    //Assume you have many dependencies and you want to set up all the stubs 
    //in one place assuming that all your tests need these stubs.

    //I know that any initialization code for the test can/should be in a 
    //@Before method. Lets assume there is another method just to create 
    //your stubs.

    public void setUpRequiredStubs() {
        when(svc1Mock1.someMethod(any(), any())).thenReturn(something));
        when(svc2Mock2.someOtherMethod(any())).thenReturn(somethingElse);
    }

    @Test
    public void methodUnderTest_StateUnderTest_ExpectedBehavior() {
        // You forget that you defined the stub for svcMock1.someMethod or 
        //thought you could redefine it. Well you cannot. That's going to be 
        //a problem and would throw your UnnecessaryStubbingException.
       when(svc1Mock1.someMethod(any(),any())).thenReturn(anyThing);//ERROR!
       setUpRequiredStubs();
    }
}

Ich würde lieber in Betracht ziehen, Ihre Tests zu überarbeiten, um sie bei Bedarf zu stoppen.

Railomaya
quelle
2

Wenn Sie stattdessen diesen Stil verwenden:

@Rule
public MockitoRule rule = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);

Ersetzen Sie es durch:

@Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
Greg
quelle
1

Ich hatte, UnnecessaryStubbingExceptionals ich versuchte, die whenMethoden auf ein Spy-Objekt anzuwenden. Mockito.lenient()Die Ausnahme wurde zum Schweigen gebracht, aber die Testergebnisse waren nicht korrekt.

Bei Spy-Objekten muss man die Methoden direkt aufrufen.

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
class ArithmTest {

    @Spy
    private Arithm arithm;

    @Test
    void testAddition() {

        int res = arithm.add(2, 5);

        // doReturn(7).when(arithm).add(2, 5);
        assertEquals(res, 7);
    }
}
Jan Bodnar
quelle
1

In meinem Fall sagte mir der Mockito-Fehler, ich solle die eigentliche Methode nach dem whenoder aufrufenwhenever stub . Da wir uns nicht auf die Bedingungen beriefen, die wir gerade verspottet hatten, meldete Mockito dies als unnötige Stubs oder Code.

So war es, als der Fehler kam:

@Test
fun `should return error when item list is empty for getStockAvailability`() {
    doAnswer(
        Answer<Void> { invocation ->
            val callback =
                invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
            callback.onApiCallError(stockResultViewStateError)
            null
        }
    ).whenever(stockViewModelTest)
        .getStockAvailability(listOf(), getStocksApiCallBack)
}

dann habe ich gerade die in der when-Anweisung erwähnte Methode aufgerufen, um die Methode zu verspotten.

Die vorgenommenen Änderungen sind wie folgt stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)

@Test
fun `should return error when item list is empty for getStockAvailability`() {
    doAnswer(
        Answer<Void> { invocation ->
            val callback =
                invocation.arguments[1] as GetStockApiCallback<StockResultViewState.Idle, StockResultViewState.Error>
            callback.onApiCallError(stockResultViewStateError)
            null
        }
    ).whenever(stockViewModelTest)
        .getStockAvailability(listOf(), getStocksApiCallBack)
    //called the actual method here
    stockViewModelTest.getStockAvailability(listOf(), getStocksApiCallBack)
}

es funktioniert jetzt.

vikas kumar
quelle
1

Ersetzen

@RunWith(MockitoJUnitRunner.class)

mit

@RunWith(MockitoJUnitRunner.Silent.class)

oder entfernen@RunWith(MockitoJUnitRunner.class)

oder kommentieren Sie einfach die unerwünschten Spottanrufe aus (angezeigt als nicht autorisiertes Stubbing).

Nakul Goyal
quelle
0

Bei einem großen Projekt ist es schwierig, jede dieser Ausnahmen zu beheben. Zur gleichen Zeit mitSilent nicht empfohlen. Ich habe ein Skript geschrieben, um alle unnötigen Stubbings zu entfernen, die eine Liste von ihnen enthalten.

https://gist.github.com/cueo/da1ca49e92679ac49f808c7ef594e75b

Wir müssen nur die mvnAusgabe kopieren und einfügen und die Liste dieser Ausnahmen mit Regex schreiben und das Skript den Rest erledigen lassen.

Mohitmayank
quelle
0

Wenn Sie beim Verspotten any () verwenden, müssen Sie @RunWith (MockitoJUnitRunner.class) mit @RunWith (MockitoJUnitRunner.Silent.class) neu platzieren.

Abdou ASSOUMANE
quelle
0

Wenn Sie ein Modell erstellen und dieses Modell nicht verwendet wird, wird eine nicht verwendete Stubbing-Ausnahme ausgelöst. In Ihrem Fall wird dieser Schein nicht wirklich genannt. Daher wird dieser Fehler ausgelöst. Daher relpace, @RunWith(MockitoJUnitRunner.class)mit @RunWith(MockitoJUnitRunner.Silent.class)dem der Fehler behoben werden würde. Wenn Sie weiterhin verwenden möchten, @RunWith(MockitoJUnitRunner.class)versuchen Sie, Ihre Logik zu debuggen, ob die von Ihnen verspottete Funktion tatsächlich aufgerufen wird oder nicht.

Shivam Kohli
quelle