1. Overview
In this quick tutorial, we’ll learn about the Mockito UnnecessaryStubbingException. This exception is a common exception we’ll likely encounter when using stubs incorrectly.
We’ll start by explaining the philosophy behind strict stubbing, and why Mockito encourages its use by default. Then we’ll take a look at exactly what this exception means, and under what circumstances it can occur. Finally, we’ll see an example of how we can suppress this exception in our tests.
To learn more about testing with Mockito, check out our comprehensive Mockito series.
2. Strict Stubbing
With version 1.x of Mockito, it was possible to configure and interact with mocks without restrictions. This meant that, over time, tests would often become overcomplicated, and at times harder to debug.
Since version 2.+, Mockito has been introducing new features that nudge the framework towards “strictness.” The main goals behind this are:
- Detect unused stubs in the test code
- Reduce test code duplication and unnecessary test code
- Promote cleaner tests by removing ‘dead’ code
- Help improve debuggability and productivity
Following these principles helps us create cleaner tests by eliminating unnecessary test code. They also help us avoid copy-paste errors, as well as other developer oversights.
To summarise, strict stubbing reports unnecessary stubs, detects stubbing argument mismatch, and makes our tests more DRY (Don’t Repeat Yourself). This facilitates a clean and maintainable codebase.
2.1. Configuring Strict Stubs
Since Mockito 2.+, strict stubbing is used by default when initializing our mocks using either:
- MockitoJUnitRunner
- MockitoJUnit.rule()
Mockito strongly recommends the use of either of the above. However, there’s also another way to enable strict stubbing in our tests when we’re not leveraging the Mockito rule or runner:
Mockito.mockitoSession()
.initMocks(this)
.strictness(Strictness.STRICT_STUBS)
.startMocking();
One last important point to make is that in Mockito 3.0, all stubbings will be “strict” and validated by default.
3. UnnecessaryStubbingException Example
Simply put, an unnecessary stub is a stubbed method call that was never realized during test execution.
Let’s take a look at a simple example:
@Test
public void givenUnusedStub_whenInvokingGetThenThrowUnnecessaryStubbingException() {
when(mockList.add("one")).thenReturn(true); // this won't get called
when(mockList.get(anyInt())).thenReturn("hello");
assertEquals("List should contain hello", "hello", mockList.get(1));
}
When we run this unit test, Mockito will detect the unused stub and throw an UnnecessaryStubbingException:
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 com.baeldung.mockito.misusing.MockitoUnecessaryStubUnitTest.givenUnusedStub_whenInvokingGetThenThrowUnnecessaryStubbingException(MockitoUnecessaryStubUnitTest.java:37)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.
Thankfully, it’s quite clear from the error message what the problem is here. We can also see that the exception message even points us to the exact line which causes the error.
Why does this happen? Well, the first when invocation configures our mock to return true when we call the add method with the argument “one.” However, we don’t then invoke this method during the rest of the unit test execution.
Mockito is telling us that our first when line is redundant, and perhaps we made an error when configuring our stubs.
Although this example is trivial, it’s easy to imagine when mocking a complex hierarchy of objects how this kind of message can assist debugging and be otherwise very helpful.
4. Bypassing Strict Stubbing
Finally, let’s see how to bypass strict stubs. This is also known as lenient stubbing.
Sometimes we need to configure specific stubbing to be lenient, while maintaining all the other stubbings and mocks to use strict stubbing:
@Test
public void givenLenientdStub_whenInvokingGetThenThrowUnnecessaryStubbingException() {
lenient().when(mockList.add("one")).thenReturn(true);
when(mockList.get(anyInt())).thenReturn("hello");
assertEquals("List should contain hello", "hello", mockList.get(1));
}
In the above example, we use the static method Mockito.lenient() to enable the lenient stubbing on the add method of our mock list.
Lenient stubs bypass “strict stubbing” validation rules. For example, when stubbing is declared as lenient, it won’t be checked for potential stubbing problems, such as the unnecessary stubbing described earlier.
5. Conclusion
In this brief article, we introduced the concept of strict stubbing in Mockito, detailing the philosophy behind why it was introduced and why it’s important.
Then we looked at an example of the UnnecessaryStubbingException, before finishing with an example of how to enable lenient stubbing in our tests.
As always, the full source code of the article is available over on GitHub.