Checking calls: verify
Some methods return nothing useful — their job is a side effect. publish() must save the post and send a notification; the result of notifier.send() is void, there is nothing to compare with assertEquals. For such cases a mock remembers every call it received, and verify checks that the expected call happened.
verify
// src/test/java/com/example/blog/PostServiceVerifyTest.java
package com.example.blog;
import org.junit.jupiter.api.Test;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.*;
class PostServiceVerifyTest {
private final PostRepository repository = mock(PostRepository.class);
private final Notifier notifier = mock(Notifier.class);
private final PostService service = new PostService(repository, notifier);
@Test
void publishSavesPostAndNotifiesAuthor() {
when(repository.findById(1L))
.thenReturn(Optional.of(new Post(1L, "Hello", "anna", false)));
service.publish(1L);
verify(repository).save(new Post(1L, "Hello", "anna", true));
verify(notifier).send("anna", "Your post \"Hello\" is published");
}
}verify(notifier).send(...) reads as "check that send was called with these arguments". The arguments are compared with equals(); for a record this compares all fields, so the first line also checks that the saved post is published. The mocks are created in fields: JUnit makes a new instance of the class for every test, so each test gets fresh mocks.
How many times
The second argument of verify sets the number of calls:
| Mode | Meaning |
|---|---|
verify(mock) | Exactly once, the same as times(1) |
times(2) | Exactly twice |
never() | Never |
atLeastOnce(), atLeast(2), atMost(3) | At least / at most |
// src/test/java/com/example/blog/PostServiceVerifyTest.java
@Test
void unknownPostIsNotSaved() {
when(repository.findById(99L)).thenReturn(Optional.empty());
assertThrows(PostNotFoundException.class, () -> service.publish(99L));
verify(repository, never()).save(new Post(99L, "Hello", "anna", true));
verifyNoInteractions(notifier);
}verifyNoInteractions(notifier) checks that the notifier was not touched at all — nobody should receive an email about a post that does not exist. verifyNoMoreInteractions(mock) after a few verify calls checks that there were no other calls besides those already verified.
Mockito's messages
If the service sent a different text, Mockito shows both the expected and the actual call:
Argument(s) are different! Wanted:
notifier.send(
"anna",
"Post "Hello" is published"
);
-> at com.example.blog.VerifyFailTest.wrongArguments(VerifyFailTest.java:25)
Actual invocations have different arguments at position [1]:
notifier.send(
"anna",
"Your post "Hello" is published"
);
-> at com.example.blog.PostService.publish(PostService.java:30)position [1] is the second argument (counting from zero). When the number of calls is wrong:
org.mockito.exceptions.verification.TooFewActualInvocations:
postRepository.findById(1L);
Wanted 2 times:
-> at com.example.blog.VerifyFailTest.tooMany(VerifyFailTest.java:42)
But was 1 time:
-> at com.example.blog.PostService.find(PostService.java:23)When to verify
Check calls only where they are the result of the method: a saved post, a sent message. Do not verify every findById — such a test breaks after any refactoring, even when the behavior is the same. If the result can be checked through a return value, prefer assertEquals.
Common mistake
The test calls verify but the code under test was never run, or ran with different data:
Wanted but not invoked:
notifier.send(
"anna",
"Your post "Hello" is published"
);
-> at com.example.blog.VerifyFailTest.notInvoked(VerifyFailTest.java:32)
Actually, there were zero interactions with this mock.Here the test called service.published() instead of service.publish(1L). "Zero interactions" means the mock was not called at all — check that the act part calls the right method and that the service received this very mock.