12

I have a unit test class where my unit under test is dependent on another class. The dependency is mocked using Mockito and then setup with a generic stub that's run before every unit test, using JUnit's @BeforeEach annotation. See the below pseudo-code.

@ExtendWith(MockitoExtension.class)
public class FooFactoryTest {

    @Mock
    private BarDependency barDependency;

    @InjectMocks
    private FooFactory unitUnderTest;

    @BeforeEach
    public void setup() {
        when(barDependency.leftBar(any())).thenReturn(new Bar());
        when(barDependency.rightBar(any())).thenReturn(new Bar());
    }

   ... many tests ...

This setup works perfectly for 9 of my 10 unit tests. Unfortunately one of my tests is failing with the following error:

org.mockito.exceptions.misusing.UnnecessaryStubbingException: 
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
  1. -> at nl.devillers.mockito.FooFactoryTest.setup(FooFactoryTest.java:69)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.

Now, I understand the error and why it's thrown, because in that specific test my unit under test short-circuits early and doesn't hit all the stubs that have been setup. I'm aware there's a lenient option in Mockito, but that'll disable the check for the entire class/project.

My question is: how do I disable this strictness for one specific unit test?

Again: I do not want to disable the strictness at the class or project level, since I think it's valuable check. I also do not want to move my setup code to the tests that do need the stubs, because then I have to duplicate the setup code nine times. In this case I just want to disable or skip the check for this specific test.

Martin Devillers
  • 17,293
  • 5
  • 46
  • 88

3 Answers3

6

You can avoid this check at the test-level by resetting the mock with the stub that's not being called. This is a bit of a work around, but it'll allow you to pass your test without having to make the mock lenient for your entire test class or removing the mock entirely from your setup method.

To reset your barDependency mock, add the following line of code to the end of your test that is failing with a UnnecessaryStubbingException.

Mockito.reset(barDependency);

If none of the stubs on barDependency are being used, you can also place this line at the beginning of your test with your other arrangements, which is a little cleaner. Or alternately, put it at the top of your test method and then setup the stubs you do need. This essentially overrides whatever is being setup in your generic setup method.

Martin Devillers
  • 17,293
  • 5
  • 46
  • 88
4

You can also use lenient in the code of your @BeforeEach, like this:

@BeforeEach
public void setup() {
    lenient().when(barDependency.leftBar(any())).thenReturn(new Bar());
    lenient().when(barDependency.rightBar(any())).thenReturn(new Bar());
}

This should not be necessary, based on this doc in the UnnecessaryStubbingException:

Mockito JUnit Runner triggers UnnecessaryStubbingException only when none of the test methods use the stubbings. This means that it is ok to put default stubbing in a 'setup' method or in test class constructor. That default stubbing needs to be used at least once by one of the test methods.

Bruno Medeiros
  • 2,251
  • 21
  • 34
  • 4
    I had to use lenient as well. I see the documentation, I don't understand why it doesn't work but I'm using mockito 4.0.0 and JUnit 5.8.2 and MockitoExtension and it does not matter if there's another test that uses the stub, EVERY test must use the stub or it fails. – Jason Winnebeck Apr 21 '22 at 19:54
  • Like I mentioned in the question this approach will disable strictness in all the tests. If this acceptable for your use case then that's ok, but in my scenario I only wanted to disable this check for one specific test. It's interesting that Mockito documentation says it should be lenient by default for stubs defined in a 'setup' method-- I have never observed Mockito to actually be that intelligent. In my projects Mockito treats stubs the same way regardless if they're defined in a test method or setup method. – Martin Devillers Aug 31 '22 at 15:26
2

I'm aware there's a lenient option in Mockito, but that'll disable the check for the entire class/project.

My question is: how do I disable this strictness for one specific unit test?

You can, in fact, apply the lenient option to a single test:

@Test
@MockitoSettings(strictness = Strictness.LENIENT)
public void myTest() {
    // ...
}
Rapti
  • 2,520
  • 3
  • 20
  • 23