This rule raises an issue when test mock stubbing is syntactically incomplete.

In Mockito, this means: a when() call must be followed by thenReturn(), thenThrow(), thenAnswer(), or thenCallRealMethod(); and a doReturn(), doThrow(), doAnswer(), doNothing(), or doCallRealMethod() call must be followed by .when(mock).method().

Why is this an issue?

Test double frameworks allow you to configure behavior through chained API calls. These chains must be syntactically complete to take effect.

When you write the first part of a stub configuration (specifying which method call to intercept) without completing the chain with a behavior specification (what value to return or action to take), the configuration is discarded. The method continues to return its default value (null for objects, 0 for numbers, false for booleans).

Similarly, when you write the behavior specification first (what to return) without completing it with the method specification (which method to stub), the configured behavior is never attached to any method. It is silently dropped.

Both patterns compile and run without errors in lenient testing frameworks. This makes them hard to spot during code review or testing. The test may pass because it never actually exercises the intended stub, or it may fail with a confusing error message that doesn’t point to the incomplete stubbing.

The incomplete stub creates a gap between what you intended to test and what the test actually verifies. This undermines the reliability of your test suite.

What is the potential impact?

Incomplete mock object stubs can cause:

How to fix it in Mockito

Complete the when() chain by adding a behavior method such as thenReturn(), thenThrow(), thenAnswer(), or thenCallRealMethod().

Code examples

Noncompliant code example

@Test
void testFindUser() {
  UserRepository mock = mock(UserRepository.class);
  when(mock.findUser(42)); // Noncompliant

  User user = service.getUser(42);
  assertNotNull(user); // Will fail - findUser returns null
}

Compliant solution

@Test
void testFindUser() {
  UserRepository mock = mock(UserRepository.class);
  when(mock.findUser(42)).thenReturn(new User("Alice"));

  User user = service.getUser(42);
  assertNotNull(user); // Now passes correctly
}

Complete the do*() chain by adding .when(mock).method() to specify which method should have the configured behavior.

Noncompliant code example

@Test
void testDeleteUser() {
  UserRepository mock = mock(UserRepository.class);
  doThrow(new RuntimeException()); // Noncompliant

  assertThrows(RuntimeException.class, () -> {
    service.deleteUser(42);
  }); // Will fail - no exception is thrown
}

Compliant solution

@Test
void testDeleteUser() {
  UserRepository mock = mock(UserRepository.class);
  doThrow(new RuntimeException()).when(mock).deleteUser(42);

  assertThrows(RuntimeException.class, () -> {
    service.deleteUser(42);
  }); // Now passes correctly
}

Resources

Documentation

Related rules