Mockito中Stub符合文档却抛出UnfinishedStubException问题求助
Hey there, let's break down this frustrating UnfinishedStubException issue you're facing—this error usually pops up when Mockito detects that your stubbing setup isn't fully completed, even if it looks like you followed the docs. Let's go through the most common fixes step by step:
Common Causes & Fixes
1. Incomplete Stubbing Chain
The most frequent culprit is a broken doThrow() chain. You need to explicitly link the exception to a specific method on your mock object—just calling doThrow() alone isn't enough.
Wrong:
// Missing the target method and mock association doThrow(new IllegalArgumentException("Invalid input"));
Right:
For void methods (the primary use case for doThrow()):
// Complete chain: specify exception → target mock → target method doThrow(new IllegalArgumentException("Invalid input")) .when(myMock) .myVoidMethod();
For non-void methods (if you need to bypass the default when().thenThrow() behavior):
doThrow(new IllegalStateException("Operation failed")) .when(myMock) .myReturningMethod();
2. Accidental Real Method Invocation
It's easy to accidentally trigger a real method call while setting up stubs, which breaks the stubbing process. Make sure you don't call the mock method inside the when() parentheses.
Wrong:
// This calls myMethod() directly, causing real execution and incomplete stubbing doThrow(new Exception()) .when(myMock.myMethod());
Right:
// Pass the mock to when(), then specify the method without invoking it doThrow(new Exception()) .when(myMock) .myMethod();
3. Uninitialized Mocks
If you're using @Mock annotations, double-check that you've initialized your mocks properly. Without initialization, Mockito can't recognize the object as a mock, leading to unexpected errors.
For JUnit 5:
@ExtendWith(MockitoExtension.class) public class MyTestClass { @Mock private MyService myService; // Your test methods here }
For JUnit 4:
@RunWith(MockitoJUnitRunner.class) public class MyTestClass { @Mock private MyService myService; // Your test methods here }
If you're not using annotations, initialize mocks manually in your setup method:
@BeforeEach void setUp() { myService = Mockito.mock(MyService.class); }
4. Crossed Stubbing Operations
Sometimes mixing multiple stubbing operations in the same test can cause incomplete stubs. Ensure each doThrow() (or other stubbing) is fully completed before moving to the next one.
Avoid:
// Starting one stub and switching to another before finishing doThrow(new RuntimeException()) .when(myMock); // Interrupting the first stub to start another when(myOtherMock.someMethod()).thenReturn("value");
Do:
// Complete each stub fully before moving on doThrow(new RuntimeException()) .when(myMock) .myMethod(); when(myOtherMock.someMethod()).thenReturn("value");
5. Mockito Version Compatibility
Occasionally, older versions of Mockito have bugs with certain stubbing patterns. Try upgrading to the latest stable version of Mockito to rule out version-related issues.
Example Working Test
Here's a full example that correctly uses doThrow() and validates the exception:
@ExtendWith(MockitoExtension.class) public class ServiceExceptionTest { @Mock private UserService userService; @Test void testDeleteUser_ThrowsException() { // Setup stub: throw exception when deleteUser is called with ID 1 doThrow(new UserNotFoundException("User not found")) .when(userService) .deleteUser(1L); // Verify the exception is thrown UserNotFoundException exception = assertThrows(UserNotFoundException.class, () -> userService.deleteUser(1L)); assertEquals("User not found", exception.getMessage()); } }
If you've tried all these steps and still hit the error, sharing a snippet of your actual test code would help pinpoint the issue further—but these fixes resolve 90% of UnfinishedStubException cases with doThrow().
内容的提问来源于stack exchange,提问作者Vlad Balanescu

