Jak rozwiązać niepotrzebny wyjątek zatarcia

104

Mój kod jest jak poniżej,

@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);

      }
}

Jestem poniżej wyjątku

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)

Pomóż mi, jak to rozwiązać

VHS
źródło

Odpowiedzi:

118

Wymień @RunWith(MockitoJUnitRunner.class)się @RunWith(MockitoJUnitRunner.Silent.class).

Sumit
źródło
44
Witamy. warto zaktualizować swoją odpowiedź, aby wyjaśnić, dlaczego OP powinni zastąpić taki kod. Pomoże im to i przyszłym odwiedzającym zrozumieć.
Błędy
5
Przy okazji, jest @RunWith(MockitoJUnitRunner.Silent.class)i nie jest CICHY
fgysin przywraca Monikę
6
W Kotlinie:@RunWith(MockitoJUnitRunner.Silent::class)
Juan Saravia
11
Nie jestem pewien, dlaczego ta odpowiedź jest wciąż pozytywna bez wyjaśnienia. Inne odpowiedzi są bardziej znaczące i dokładne.
Yogesh
10
Nie rozwiązuje to problemu, ale po prostu usuwa komunikat o błędzie i wpłynie również na wszystkie inne testy (jeśli występują) w klasie.
Fencer
104

Najpierw sprawdź logikę testu. Zwykle są 3 przypadki. Po pierwsze, kpisz z niewłaściwej metody (popełniłeś literówkę lub ktoś zmienił testowany kod, tak że fałszywa metoda nie jest już używana). Po drugie, test kończy się niepowodzeniem przed wywołaniem tej metody. Po trzecie, twoja logika popada w błąd, jeśli / switch gałąź gdzieś w kodzie, więc mockowana metoda nie zostanie wywołana.

Jeśli jest to pierwszy przypadek, zawsze chcesz zmienić mockowaną metodę na używaną w kodzie. Z drugim i trzecim to zależy. Zwykle powinieneś po prostu usunąć tę makietę, jeśli nie ma ona zastosowania. Ale czasami w sparametryzowanych testach są pewne przypadki, które powinny pójść tą inną ścieżką lub zakończyć się niepowodzeniem wcześniej. Następnie możesz podzielić ten test na dwa lub więcej oddzielnych, ale nie zawsze wygląda to dobrze. 3 metody testowe z maksymalnie 3 argumentami, które dostawcy mogą sprawić, że test będzie wyglądał nieczytelnie. W takim przypadku dla JUnit 4 możesz wyciszyć ten wyjątek z jednym i drugim

@RunWith(MockitoJUnitRunner.Silent.class) 

adnotacja lub jeśli używasz podejścia regułowego

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

lub (to samo zachowanie)

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

W przypadku testów JUnit 5 można wyciszyć ten wyjątek za pomocą adnotacji dostarczonej w mockito-junit-jupiterpakiecie.

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class JUnit5MockitoTest {
}
Dcortez
źródło
3
@MockitoSettings (rictness = Strictness.LENIENT) to najprostszy sposób dostosowania ścisłości w mojej konfiguracji. Dzięki!
Matt,
7
Ta odpowiedź zapewnia dobry przegląd możliwości. Możesz jednak ustawić łagodną restrykcyjność dla każdego przypadku za pomocą Mockito.lenient().when(...); dla tego konkretnego pytania byłobyMockito.lenient().when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);
neXus
Zdefiniuj ExtendWith w nadklasie i MockitoSettings w podklasach, gdy zajmujesz się hierarchiami testów. Mam nadzieję, że zaoszczędzi to komuś czasu na mój koszt.
miracle_the_V
37

Milczenie nie jest rozwiązaniem. Musisz poprawić swoją próbę w swoim teście. Zobacz oficjalną dokumentację tutaj .

Niepotrzebne kody pośredniczące to wywołania metod, które nigdy nie zostały zrealizowane podczas wykonywania testu (zobacz także MockitoHint), przykład:

//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
 ...

Zauważ, że jedna z metod skrótowych nigdy nie została zrealizowana w testowanym kodzie podczas wykonywania testu. Zagubiony fragment może być przeoczeniem dewelopera, artefaktem kopiowania i wklejania lub skutkiem niezrozumienia testu / kodu. Tak czy inaczej, programista kończy z niepotrzebnym kodem testowym. Aby baza kodu była czysta i łatwa do utrzymania, konieczne jest usunięcie niepotrzebnego kodu. W przeciwnym razie testy są trudniejsze do odczytania i uzasadnienia.

Aby dowiedzieć się więcej o wykrywaniu nieużywanych kiczów, zobacz MockitoHint.

Stéphane GRILLON
źródło
14
Istnieje wiele sytuacji, w których piszesz 8-9 testów dla podobnej konfiguracji @BeforeEach, w których zwracany element z jednego kodu pośredniczącego jest nieużywany ze względu na logikę biznesową w kilku testach. Możesz (A) podzielić to na wiele testów i skutecznie skopiować / wkleić sekcję \ @BeforeEach minus jeden element (B) Skopiować / wkleić pojedynczą linię, którą Mockito jest emo, do 6 testów, które go używają i mieć to nie w 2, które nie lub (C) Użyj cichego. Wolę używać cichego / ostrzegawczego. To nie jest zepsuty test.
RockMeetHardplace
1
@RockMeetHardplace, Silent nie jest rozwiązaniem , szybko widać mniej kopiowania / wklejania, ale podczas utrzymywania testów przez nowe osoby w projekcie będzie to problematyczne. Jeśli księgarnia Mockito to robi, to nie na darmo.
Stéphane GRILLON
2
@sgrillon: Ale ten system wykrywa mnóstwo fałszywych alarmów. Oznacza to, że mówi, że coś jest nieużywane, ale wyraźnie nie jest, ponieważ usunięcie kodu przerywa wykonanie. Nie chodzi o to, że kodu testowego nie można ulepszyć, ale o to, że istotna linia kodu zgubienia nie powinna nigdy zostać wykryta jako „niepotrzebna”. Dlatego ważne jest, aby móc wyłączyć tę kontrolę, jest zbyt chętna.
Carighan
1
@ Carighan, jeśli Twoja próba zostanie wykryta jako nieprawidłowa, może to nie być to, co myślisz. To daje ci test OK, podczas gdy może być błąd.
Stéphane GRILLON
@sgrillon, przepraszam, że nie odezwałem się w tej sprawie. Okazuje się, że był w tym błąd, który polegał na tym, że w zależności od kolejności wykonania testu generował „fałszywe trafienia”, gdzie kody pośredniczące, które były używane w jednym teście, ale nadpisywane w innym, uruchamiały go. O ile wiem, jest to naprawione od dawna.
Carighan
32

U mnie ani te, @Ruleani @RunWith(MockitoJUnitRunner.Silent.class)sugestie nie zadziałały. To był starszy projekt, w którym zaktualizowaliśmy do mockito-core 2.23.0.

Mogliśmy się go pozbyć UnnecessaryStubbingExceptionza pomocą:

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

zamiast:

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

Nie trzeba dodawać, że powinieneś raczej spojrzeć na kod testowy, ale musieliśmy najpierw skompilować rzeczy i testy;)

filoniczny
źródło
8
MOIM ZDANIEM. Jest to najbardziej przydatna odpowiedź, którą znalazłem zamiast wyciszenia całej klasy testowej.
priyeshdkr
1
Ponieważ chciałem stłumić tylko 1 kpinę, jest to dla mnie najlepsza odpowiedź. Jednak nie jest to odpowiedź na OP.
Hans Wouters
25
 when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
 verify(dao).doSearchInspections(dto);

whenTutaj konfiguruje makiety coś zrobić. Jednak po tej linijce nie używasz już w żaden sposób tej makiety (poza zrobieniem a verify). Mockito ostrzega, że ​​w whenzwiązku z tym linia jest bezcelowa. Być może popełniłeś błąd logiczny?

john16384
źródło
Dzięki za pomoc
VHS
Potrzebuję zarówno kiedy, jak i zweryfikować oświadczenia uprzejmie podpowiadają jak pójść dalej
VHS
2
Wywołaj funkcję w swojej klasie testowej ( Service), aby sprawdzić, czy działa poprawnie. W ogóle tego nie zrobiłeś, więc co tutaj testujesz?
john16384
3

Patrząc na część śladu stosu, wygląda na to, że przegrywasz dao.doSearch()gdzie indziej. Bardziej przypomina wielokrotne tworzenie kodów pośredniczących tej samej metody.

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.

Rozważ na przykład poniższą klasę testową:

@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();
    }
}

Wolałbym raczej rozważyć refaktoryzację twoich testów, aby zablokować je w razie potrzeby.

railomaya
źródło
1

Jeśli zamiast tego używasz tego stylu:

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

zamień na:

@Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
Greg
źródło
1

Miałem, UnnecessaryStubbingExceptiongdy próbowałem użyć whenmetod na obiekcie szpiegowskim. Mockito.lenient()wyciszył wyjątek, ale wyniki testu były nieprawidłowe.

W przypadku obiektów Spy należy wywołać metody bezpośrednio.

@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
źródło
1

Cóż, w moim przypadku błąd Mockito mówił mi, żebym wywołał właściwą metodę po whenlubwhenever . Ponieważ nie wywoływaliśmy warunków, z których przed chwilą wyśmiewaliśmy, Mockito zgłosił to jako niepotrzebne kody pośredniczące lub kod.

Oto jak to było, kiedy nadchodził błąd:

@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)
}

następnie właśnie wywołałem właściwą metodę wspomnianą w instrukcji when, aby kpić z metody.

wprowadzone zmiany są jak poniżej 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)
}

już działa.

vikas kumar
źródło
1

Zastąpić

@RunWith(MockitoJUnitRunner.class)

z

@RunWith(MockitoJUnitRunner.Silent.class)

lub usuń@RunWith(MockitoJUnitRunner.class)

lub po prostu zakomentuj niechciane kpiące połączenia (pokazane jako nieautoryzowane stubbing).

Nakul Goyal
źródło
0

W przypadku dużego projektu trudno jest naprawić każdy z tych wyjątków. W tym samym czasie, używającSilent nie zaleca się . Napisałem skrypt, aby usunąć wszystkie niepotrzebne karczowce, podając ich listę.

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

Musimy tylko skopiować i wkleić mvnwynik i napisać listę tych wyjątków za pomocą wyrażenia regularnego, a skrypt zajmie się resztą.

mohitmayank
źródło
-1

Jeśli używasz any () podczas mockowania, musisz zamienić miejsce @RunWith (MockitoJUnitRunner.class) z @RunWith (MockitoJUnitRunner.Silent.class).

Abdou ASSOUMANE
źródło
To jest po prostu fałszywe. any()działa doskonale ze zwykłym biegaczem, gdy jest prawidłowo używany.
Matthew Przeczytaj
-1

Kiedy tworzysz makietę i ta makieta nie jest używana, zgłasza nieużywany wyjątek stubbing. W twoim przypadku ten mock nie jest faktycznie wywoływany. Dlatego rzuca ten błąd. W związku @RunWith(MockitoJUnitRunner.class)z @RunWith(MockitoJUnitRunner.Silent.class)tym zmiana miejsca z którą usunie błąd. Jeśli nadal chcesz użyć, @RunWith(MockitoJUnitRunner.class)spróbuj debugować swoją logikę, jeśli funkcja, którą mockujesz, jest faktycznie wywoływana, czy nie.

Shivam Kohli
źródło
Nie dodaje to niczego, co nie zostało uwzględnione w istniejących odpowiedziach.
Matthew Read