Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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:

ModeMeaning
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.

Thanks for reading!

Donate to the site — we work hard for you.