Bagaimana mengatasi pengecualian Stubbing yang Tidak Diperlukan


104

Kode Saya adalah seperti di bawah ini,

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

      }
}

Saya mendapatkan pengecualian di bawah ini

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)

Tolong bantu saya bagaimana menyelesaikannya

Jawaban:


118

Ganti @RunWith(MockitoJUnitRunner.class)dengan @RunWith(MockitoJUnitRunner.Silent.class).


44
Selamat datang. sebaiknya memperbarui jawaban Anda untuk menjelaskan mengapa mereka OP harus mengganti kode tersebut. Ini akan membantu mereka dan pengunjung yang akan datang untuk mengerti.
Bugs

5
Btw, itu @RunWith(MockitoJUnitRunner.Silent.class)dan tidak SILENT
fgysin mengembalikan Monica

6
Di Kotlin:@RunWith(MockitoJUnitRunner.Silent::class)
Juan Saravia

11
Tidak yakin mengapa jawaban ini terus mendapat suara positif tanpa penjelasan. Jawaban lain lebih bermakna dan akurat.
Yogesh

10
Ini tidak menyelesaikan masalah, tetapi cukup menekan pesan kesalahan dan juga akan mempengaruhi semua tes lainnya (jika ada) di kelas.
Pemain anggar

104

Pada awalnya, Anda harus memeriksa logika pengujian Anda. Biasanya ada 3 kasus. Pertama, Anda mengejek metode yang salah (Anda salah ketik atau seseorang mengubah kode yang diuji sehingga metode yang diejek tidak lagi digunakan). Kedua, pengujian Anda gagal sebelum metode ini dipanggil. Ketiga, logika Anda salah jika / switch cabang di suatu tempat dalam kode sehingga metode yang diejek tidak dipanggil.

Jika ini kasus pertama, Anda selalu ingin mengubah metode tiruan untuk metode yang digunakan dalam kode. Dengan yang kedua dan ketiga itu tergantung. Biasanya Anda harus menghapus tiruan ini jika tidak ada gunanya. Tapi terkadang ada kasus tertentu dalam tes parametrized, yang harus mengambil jalur yang berbeda ini atau gagal lebih awal. Kemudian Anda dapat membagi tes ini menjadi dua atau lebih tes terpisah tetapi itu tidak selalu bagus. 3 metode pengujian dengan kemungkinan 3 penyedia argumen dapat membuat pengujian Anda terlihat tidak terbaca. Dalam kasus untuk JUnit 4 Anda membungkam pengecualian ini dengan baik

@RunWith(MockitoJUnitRunner.Silent.class) 

anotasi atau jika Anda menggunakan pendekatan aturan

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

atau (perilaku yang sama)

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

Untuk pengujian JUnit 5 Anda dapat membungkam pengecualian ini dengan menggunakan anotasi yang disediakan dalam mockito-junit-jupiterpaket.

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class JUnit5MockitoTest {
}

3
@MockitoSettings (strictness = Strictness.LENIENT) adalah cara termudah untuk menyesuaikan keketatan dalam pengaturan saya. Terima kasih!
Matt

7
Jawaban ini memberikan gambaran umum yang bagus tentang kemungkinannya. Namun, Anda juga dapat menetapkan keketatan yang longgar berdasarkan kasus per kasus menggunakan Mockito.lenient().when(...); untuk pertanyaan khusus ini adalahMockito.lenient().when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);
neXus

Tentukan ExtendWith di superclass dan MockitoSettings di subclass, saat menangani hierarki pengujian. Semoga ini menghemat waktu seseorang atas biaya saya.
miracle_the_V

38

Diam bukanlah solusi. Anda perlu memperbaiki tiruan Anda dalam pengujian Anda. Lihat dokumentasi resmi di sini .

Stub yang tidak perlu adalah panggilan metode bertopik yang tidak pernah terwujud selama eksekusi pengujian (lihat juga MockitoHint), contoh:

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

Perhatikan bahwa salah satu metode yang dipotong tidak pernah direalisasikan dalam kode yang diuji, selama eksekusi uji. Stubbing yang menyimpang mungkin merupakan pengawasan dari pengembang, artefak dari copy-paste atau efek tidak memahami tes / kode. Apa pun alasannya, pengembang mendapatkan kode pengujian yang tidak perlu. Untuk menjaga basis kode tetap bersih & dapat dipelihara, perlu untuk menghapus kode yang tidak perlu. Jika tidak, tes lebih sulit untuk dibaca dan dipikirkan.

Untuk mengetahui lebih lanjut tentang mendeteksi stubbings yang tidak digunakan, lihat MockitoHint.


14
Ada banyak situasi di mana Anda menulis 8-9 pengujian terhadap penyiapan @BeforeEach serupa di mana item yang dikembalikan dari satu rintisan tidak digunakan karena logika bisnis pada beberapa pengujian. Anda dapat (A) memecahnya menjadi beberapa tes dan secara efektif menyalin / menempel bagian \ @BeforeEach minus satu item (B) Salin / tempel baris tunggal yang Mockito emo tentang ke 6 tes yang menggunakannya dan memilikinya bukan di 2 yang tidak atau (C) Gunakan diam. Saya lebih suka menggunakan silent / warn. Ini bukan tes yang rusak.
RockMeetHardplace

1
@RockMeetHardplace, Senyap bukanlah solusi , dengan cepat Anda akan melihat lebih sedikit salin / tempel tetapi saat mempertahankan pengujian oleh orang baru di proyek Anda, ini akan menjadi masalah. Jika toko buku Mockito melakukannya, itu tidak sia-sia.
Stéphane GRILLON

2
@sgrillon: Tetapi sistem ini mendeteksi banyak positif palsu. Artinya, dikatakan ada sesuatu yang tidak digunakan, tetapi jelas tidak, karena menghapus stub akan merusak eksekusi. Bukan karena kode pengujian tidak dapat ditingkatkan, tetapi baris penghentian yang penting tidak boleh dideteksi sebagai "tidak perlu". Karenanya pentingnya dapat menonaktifkan pemeriksaan ini, itu terlalu bersemangat.
Carighan

1
@Carighan, jika ejekan Anda terdeteksi sebagai salah, mungkin itu bukan yang Anda pikirkan. Ini memberi Anda tes OK sementara mungkin ada bug.
Stéphane GRILLON

@ grillon, maaf saya tidak pernah kembali kepada Anda tentang itu. Ternyata dulu ada bug dengan ini di mana bergantung pada urutan eksekusi pengujian, ia akan menghasilkan "klik palsu", di mana stub yang digunakan dalam satu pengujian tetapi ditimpa di pengujian lain akan memicunya. Ini sudah lama diperbaiki, sejauh yang saya tahu.
Carighan

32

Bagi saya @Rule, @RunWith(MockitoJUnitRunner.Silent.class)saran maupun saran itu tidak berhasil. Itu adalah proyek lama di mana kami meningkatkan ke mockito-core 2.23.0.

Kita bisa menghilangkannya UnnecessaryStubbingExceptiondengan menggunakan:

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

dari pada:

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

Tidak perlu dikatakan bahwa Anda lebih baik melihat kode pengujian, tetapi kami perlu mengkompilasi barang-barang dan pengujian berjalan terlebih dahulu;)


8
MENURUT OPINI SAYA. Ini adalah jawaban yang paling berguna di sini yang saya temukan alih-alih membungkam seluruh kelas tes.
priyeshdkr

1
Karena saya hanya ingin menahan 1 ejekan, ini adalah jawaban terbaik untuk saya. Bukan jawaban untuk OP sekalipun.
Hans Wouters

25
 when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
 verify(dao).doSearchInspections(dto);

Di whensini mengonfigurasi tiruan Anda untuk melakukan sesuatu. Namun, Anda tidak lagi menggunakan tiruan ini dengan cara apa pun setelah baris ini (selain melakukan a verify). Mockito memperingatkan Anda bahwa whengaris itu tidak ada gunanya. Mungkin Anda membuat kesalahan logika?


Terima kasih atas bantuan Anda
VHS

Saya membutuhkan keduanya kapan dan memverifikasi pernyataan dengan hormat menyarankan bagaimana untuk bergerak lebih jauh
VHS

2
Panggil fungsi pada kelas pengujian Anda ( Service) untuk melihat apakah itu bereaksi dengan benar. Anda tidak melakukan itu sama sekali, jadi apa yang Anda uji di sini?
john16384

3

Melihat bagian dari jejak tumpukan Anda, sepertinya Anda mematikan bagian dao.doSearch()lain. Lebih seperti berulang kali membuat stub dari metode yang sama.

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.

Pertimbangkan Kelas Tes di bawah ini misalnya:

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

Saya lebih suka mempertimbangkan untuk memfaktorkan ulang pengujian Anda menjadi stub jika diperlukan.


1

Jika Anda menggunakan gaya ini sebagai gantinya:

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

ganti dengan:

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

1

Saya memiliki UnnecessaryStubbingExceptionketika saya mencoba menggunakan whenmetode pada objek Spy. Mockito.lenient()membungkam pengecualian tetapi hasil tes tidak benar.

Dalam kasus objek Spy, seseorang harus memanggil metode secara langsung.

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

1

Nah, dalam kasus saya, kesalahan Mockito memberi tahu saya untuk memanggil metode sebenarnya setelah whenatau wheneverstub. Karena kami tidak menerapkan ketentuan yang baru saja kami olok, Mockito melaporkan itu sebagai stub atau kode yang tidak perlu.

Beginilah rasanya ketika kesalahan itu datang:

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

lalu saya hanya memanggil metode sebenarnya yang disebutkan dalam pernyataan when untuk mengejek metode tersebut.

perubahan yang dilakukan adalah seperti di bawah ini 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)
}

itu bekerja sekarang.


1

Menggantikan

@RunWith(MockitoJUnitRunner.class)

dengan

@RunWith(MockitoJUnitRunner.Silent.class)

atau hapus@RunWith(MockitoJUnitRunner.class)

atau hanya mengomentari panggilan mengejek yang tidak diinginkan (ditampilkan sebagai penghentian yang tidak sah).


0

Dalam kasus proyek besar, sulit untuk memperbaiki setiap pengecualian ini. Pada saat yang sama, penggunaan Silenttidak disarankan. Saya telah menulis skrip untuk menghapus semua stubbings yang tidak perlu diberikan daftar mereka.

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

Kita hanya perlu menyalin-tempel mvnoutput dan menulis daftar pengecualian ini menggunakan regex dan membiarkan skrip menangani sisanya.


-1

Jika Anda menggunakan any () saat mengejek, Anda harus mengganti spasi @RunWith (MockitoJUnitRunner.class) dengan @RunWith (MockitoJUnitRunner.Silent.class).


Ini salah. any()bekerja sempurna dengan pelari biasa bila digunakan dengan benar.
Matius Baca

-1

Saat Anda membuat tiruan dan tiruan itu tidak digunakan, ia akan mengeluarkan pengecualian stubbing yang tidak terpakai. Dalam kasus Anda, tiruan itu sebenarnya tidak dipanggil. Oleh karena itu, pelempar kesalahan itu. Oleh karena itu, relpace @RunWith(MockitoJUnitRunner.class)dengan @RunWith(MockitoJUnitRunner.Silent.class)yang akan menghapus kesalahan. Jika Anda masih ingin menggunakan @RunWith(MockitoJUnitRunner.class)coba debug logika Anda jika fungsi yang Anda tiru sebenarnya dipanggil atau tidak.


Ini tidak menambahkan apa pun yang tidak tercakup dalam jawaban yang ada.
Matius Baca
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.