210

My Code is as below,

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

      }
}

I am getting below exception

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)

Please help me how to resolve

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
VHS
  • 2,109
  • 2
  • 8
  • 4
  • This error helped me discovered a coupling issue, and leads me to write loosely coupled code. And I'd definitely not recommend bypass this using "Silent". – Enfield Li Jan 22 '23 at 18:21

14 Answers14

279

At first you should check your test logic. Usually there are 3 cases. First, you are mocking the wrong method (you made a typo or someone changed tested code so that mocked method is no longer used). Second, your test is failing before this method is called. Third, your logic falls in wrong if/switch branch somewhere in the code so that mocked method is not called.

If this is the first case you always want to change the mocked method for the one used in the code. With the second and the third it depends. Usually you should just delete this mock if it has no use. But sometimes there are certain cases in parametrized tests, which should take this different path or fail earlier. Then you can split this test into two or more separate ones but that's not always good looking. 3 test methods with possibly 3 arguments providers can make your test look unreadable. In that case for JUnit 4 you silent this exception with either

@RunWith(MockitoJUnitRunner.Silent.class) 

annotation or if you are using rule approach

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

or (the same behaviour)

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

For JUnit 5 tests you can silence this exception using this annotation provided in mockito-junit-jupiter package:

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class JUnit5MockitoTest {
}
Benjamin Zach
  • 1,452
  • 2
  • 18
  • 38
Dcortez
  • 3,716
  • 1
  • 23
  • 29
  • 4
    @MockitoSettings(strictness = Strictness.LENIENT) is the simplest way to adjust strictness in my setup. Thanks! – Matt Feb 19 '19 at 13:41
  • 49
    This answer provides a good overview of the possibilities. However, you can also set the lenient strictness on a case per case basis using `Mockito.lenient().when(...)`; for this particular question it would be `Mockito.lenient().when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);` – neXus Sep 17 '19 at 11:10
  • Define ExtendWith in superclass and MockitoSettings in subclasses, when dealing with test hierarchies. Hope this saves time for somebody on my expense. – miracle_the_V Nov 05 '19 at 07:46
  • 3
    Since 2.23.3 you can set lenient mock via annotation `@Mock(lenient = true)` – Ivan May 16 '22 at 15:44
  • Thanks, this is informative. In my case, I had added the `when` part in the `beforeEach` block. That was causing the issue. So I moved all these `when` statements to respective test so that I avoided using the lenient settings. – Ganesh Satpute Nov 11 '22 at 07:38
  • It'd be nice if you could provide the imports. For `Strictness` I see suggestions from 2 packages. `org.mockito` and `org.mockito.quality` – Arun Gowda Jun 02 '23 at 08:29
  • Another scenario I ran into (similar to logic falls in wrong if/switch branch) - I had a Base class doing my test setup, including mocking methods in a @Before method. One of my derived classes was not calling the mocked method and causing this error. – ahfx Jun 19 '23 at 20:03
150

Replace @RunWith(MockitoJUnitRunner.class) with @RunWith(MockitoJUnitRunner.Silent.class).

Eduardo
  • 6,900
  • 17
  • 77
  • 121
Sumit
  • 1,733
  • 1
  • 8
  • 4
  • 64
    Welcome. it would be well worth updating your answer to explain _why_ they OP should replace such code. This will help them and future visitors to understand. – Bugs May 22 '17 at 09:06
  • 5
    Btw, it is `@RunWith(MockitoJUnitRunner.Silent.class)` and *not* SILENT – fgysin Jun 29 '17 at 12:12
  • 8
    In Kotlin: `@RunWith(MockitoJUnitRunner.Silent::class)` – Juan Saravia Feb 16 '18 at 00:53
  • 22
    Not sure why this answer keeps getting upvote without an explanation. Other answers are more meaningful and accurate. – Yogesh D Jun 04 '19 at 13:31
  • 17
    This does not solve the problem, but simply suppress the error message and will also affect all other tests (if any) in the class. – Fencer Jul 25 '19 at 12:48
  • 5
    Please ignore this answer and remove the stubs that are not necessary – Olivier Boissé Nov 13 '19 at 16:43
  • 5
    Downvoted, since this is not a solution. You are simply hiding the issue, which is that you are mocking something, and thus are probably expecting it to be called, which isn't used. – Hans Wouters May 25 '20 at 10:56
  • Please stop assuming that everyone lives in the perfect world where all problems can be solved quickly, easily and correctly. Sometimes this just is the only way to go forward. – Torben Feb 15 '21 at 08:15
  • Because other answer give the meaning of this one – Pierre-Emmanuel Mercier Mar 20 '21 at 01:29
  • My problem was solved with this answer but I did not know exactly what is being done. Please explain what is happening – Asghar Hosseini Jun 15 '22 at 03:47
95

For me neither the @Rule nor the @RunWith(MockitoJUnitRunner.Silent.class) suggestions worked. It was a legacy project where we upgraded to mockito-core 2.23.0.

We could get rid of the UnnecessaryStubbingException by using:

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

instead of:

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

Needless to say that you should rather look at the test code, but we needed to get the stuff compiled and the tests running first of all ;)

philonous
  • 3,621
  • 3
  • 27
  • 24
68

Silent is not a solution. You need fix your mock in your test. See official documentation here.

Unnecessary stubs are stubbed method calls that were never realized during test execution (see also MockitoHint), example:

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

Notice that one of the stubbed methods were never realized in the code under test, during test execution. The stray stubbing might be an oversight of the developer, the artifact of copy-paste or the effect not understanding the test/code. Either way, the developer ends up with unnecessary test code. In order to keep the codebase clean & maintainable it is necessary to remove unnecessary code. Otherwise tests are harder to read and reason about.

To find out more about detecting unused stubbings see MockitoHint.

Stéphane GRILLON
  • 11,140
  • 10
  • 85
  • 154
  • 53
    There are many situations where you write 8-9 tests against a similar @BeforeEach setup where the returned item from one stub is unused due to business logic on a handful of tests. You can either (A) break it up into multiple tests and effectively copy/paste the \@BeforeEach section minus the one item (B) Copy/paste the single line that Mockito is emo about to the 6 tests that use it and have it not in the 2 that don't or (C) Use silent. I prefer to use silent/warn. It's not a broken test. – RockMeetHardplace Feb 27 '19 at 15:20
  • 1
    @RockMeetHardplace, **Silent is not a solution**, quickly you see less copy / paste but when maintaining your tests by new people on your project this will be problematic. If the Mockito bookstore does that it's not for nothing. – Stéphane GRILLON Feb 28 '19 at 07:36
  • 8
    @sgrillon : But this system detects loads of false-positives. That is, it says something is unused, but it's clearly not, as removing the stub breaks the execution. It's not that the test code can't be improved, it's that a vital line of stubbing should *never* be detected as "unnecessary". Hence the importance of being able to disable this check, it's too eager. – Carighan May 14 '19 at 06:51
  • 1
    @Carighan, if your mock is detected as incorrect, it may not be what you think. This gives you an OK test while there may be a bug. – Stéphane GRILLON May 14 '19 at 10:06
  • 2
    @sgrillon, sorry I never got back to you on that. It turns out that there used to be a bug with this where depending on test execution order it'd generate "false hits", where stubs that were used in one test but overwritten in another would trigger it. It's long fixed though, far as I can tell. – Carighan Mar 30 '20 at 07:31
32
 when(dao.doSearch(dto)).thenReturn(inspectionsSummaryList);//got error in this line
 verify(dao).doSearchInspections(dto);

The when here configures your mock to do something. However, you donot use this mock in any way anymore after this line (apart from doing a verify). Mockito warns you that the when line therefore is pointless. Perhaps you made a logic error?

john16384
  • 7,800
  • 2
  • 30
  • 44
10

Replace

@RunWith(MockitoJUnitRunner.class)

with

@RunWith(MockitoJUnitRunner.Silent.class)

or remove @RunWith(MockitoJUnitRunner.class)

or just comment out the unwanted mocking calls (shown as unauthorised stubbing).

Nikos Hidalgo
  • 3,666
  • 9
  • 25
  • 39
Nakul Goyal
  • 593
  • 4
  • 12
7

This was already pointed out in this comment, but I think that's too easy to overlook: You may run into an UnnecessaryStubbingException if you simply convert a JUnit 4 test class to a JUnit 5 test class by replacing an existing @Before with @BeforeEach, and if you perform some stubbing in that setup method that is not realized by at least one of the test cases.

This Mockito thread has more information on that, basically there is a subtle difference in the test execution between @Before and @BeforeEach. With @Before, it was sufficient if any test case realized the stubbings, with @BeforeEach, all cases would have to.

If you don't want to break up the setup of @BeforeEach into many small bits (as the comment cited above rightly points out), there's another option still instead of activating the lenient mode for the whole test class: you can merely make those stubbings in the @BeforeEach method lenient individually using lenient().

Hein Blöd
  • 1,553
  • 1
  • 18
  • 25
7

As others pointed out it is usually the simplest to remove the line that is unnecessarily stubbing a method call.

In my case it was in a @BeforeEach and it was relevant most of the time. In the only test where that method was not used I reset the mock, e.g.:

myMock.reset()

Hope this helps others with the same problem.

(Note that if there are multiple mocked calls on the same mock this could be inconvenient as well since you'll have to mock all the other methods except the one that isn't called.)

qben
  • 813
  • 10
  • 22
  • 1
    I like this approach. One thing though, I think the method is `reset(myMock)`, not `myMock.reset()` – L.T Feb 07 '22 at 07:46
3

Looking at a part of your stack trace it looks like you are stubbing the dao.doSearch() elsewhere. More like repeatedly creating the stubs of the same method.

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.

Consider the below Test Class for example:

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

I would rather considering refactoring your tests to stub where necessary.

djpanda
  • 835
  • 10
  • 20
3

Well, In my case Mockito error was telling me to call the actual method after the when or whenever stub. Since we were not invoking the conditions that we just mocked, Mockito was reporting that as unnecessary stubs or code.

Here is what it was like when the error was coming :

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

then I just called the actual method mentioned in when statement to mock the method.

changes done is as below 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)
}

it's working now.

vikas kumar
  • 10,447
  • 2
  • 46
  • 52
1

If you're using this style instead:

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

replace it with:

@Rule
public MockitoRule rule = MockitoJUnit.rule().silent();
Greg
  • 2,476
  • 4
  • 22
  • 28
1

I had UnnecessaryStubbingException when I tried to use the when methods on a Spy object. Mockito.lenient() silenced the exception but the test results were not correct.

In case of Spy objects, one has to call the methods directly.

@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
  • 10,969
  • 6
  • 68
  • 77
0

In case of a large project, it's difficult to fix each of these exceptions. At the same time, using Silent is not advised. I have written a script to remove all the unnecessary stubbings given a list of them.

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

We just need to copy-paste the mvn output and write the list of these exceptions using regex and let the script take care of the rest.

mohitmayank
  • 631
  • 2
  • 7
  • 20
-2

If you use any() when mocking, you have to relpace @RunWith(MockitoJUnitRunner.class) with @RunWith(MockitoJUnitRunner.Silent.class).

TuGordoBello
  • 4,350
  • 9
  • 52
  • 78