Mocking & Stubbing Basics
Creating Mocks
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void returnsUserWhenFound() {
when(userRepository.findById(1L)).thenReturn(Optional.of(new User(1L, "Ada")));
User result = userService.getUser(1L);
assertEquals("Ada", result.getName());
}
}Stubbing Returns & Exceptions
when(repo.findById(1L)).thenReturn(Optional.of(user));
when(repo.count()).thenReturn(5L, 6L, 7L); // sequential calls
when(repo.findById(99L)).thenThrow(new EntityNotFoundException());
// void methods need doThrow/doAnswer instead of when()
doThrow(new RuntimeException("db down")).when(repo).deleteById(1L);Argument Matchers
when(repo.findById(anyLong())).thenReturn(Optional.of(user));
when(repo.save(any(User.class))).thenReturn(user);
// mixing a matcher with a raw literal in the same call is not allowed —
// once you use any()/eq()/etc, every argument in that call must be a matcherMock vs. Spy
A mock() starts fully fake — every method returns a default (null/0/empty) until stubbed. A spy() wraps a real object and calls its actual methods by default, so you only stub the specific behavior you need to override.
List<String> spyList = spy(new ArrayList<>());
spyList.add("real"); // real ArrayList.add() runs
when(spyList.size()).thenReturn(100); // only size() is faked
assertEquals(100, spyList.size());Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free