
Why Mockito?
Mockito is a mocking framework that helps you test particular components of software in isolation. You use Mockito to replace collaborators of the components you’re testing so that methods in each collaborator return desired outputs for given inputs. That way, if an error occurs when testing the component, you know where and why.
Adding Mockito to the Project
First, in order to use Mockito in our project, update the Gradle build script to include JUnit and Mockito:
dependencies {
testImplementation 'junit:junit:4.13.2'
// mockito-inline is needed instead of mockito-core if you plan to mock final methods or classes, constructors, or static methods
testImplementation 'org.mockito:mockito-inline:4.11.0'
}
If this project used Maven instead of Gradle, the same two dependencies would be required, just using the Maven XML-based syntax in pom.xml.
A Test Class with Everything
A sample unit test utilizing Mockito looks like the following:
package com.example.catalog.model.pubsub;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.time.ZonedDateTime;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import com.example.catalog.exception.CatalogException;
import com.example.catalog.util.CatalogConstants;
@RunWith(MockitoJUnitRunner.class)
public class SubscriptionTest {
private static final long SUBSCRIBER_ID = 10L;
private static final long SUBSCRIPTION_ID = 100L;
private static final long NOTIFICATION_ID = 1000L;
private static final String MY_FILENAME = "thisIsMyFileName.txt";
private static final String MY_URL = "http://localhost";
@Mock
private Session mockSession;
@Mock
private HttpURLConnection mockHttpConnection;
@Mock
private Transaction mockTransaction;
private final Subscriber subscriber = new Subscriber();
private final Subscription subscription = new Subscription();
private final ZonedDateTime myDatetime = ZonedDateTime.now();
private final Notification notification = new Notification(MY_FILENAME, CatalogConstants.Changes.ADDED, myDatetime);
@Before
public void setUp() throws IOException {
subscriber.setId(SUBSCRIBER_ID);
subscriber.setEmail("abc@qc.com");
subscriber.setName("Bobby Junior");
subscription.setId(SUBSCRIPTION_ID);
subscription.setSubscriber(subscriber);
subscription.setDatasetName("myAwesomeData.s20250801.e20250802");
subscription.setRepeatingTimeIntervalString("0 0 * * *");
subscription.setUrl(MY_URL);
subscription.setTestMode(true);
notification.setId(NOTIFICATION_ID);
notification.setSubscription(subscription);
lenient().when(mockSession.beginTransaction()).thenReturn(mockTransaction);
lenient().when(mockHttpConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream());
}
@Test
public void testPublishToSuccess() throws IOException, CatalogException {
URL mockUrl = spy(URI.create(MY_URL).toURL());
when(mockUrl.openConnection()).thenReturn(mockHttpConnection);
when(mockHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_ACCEPTED);
subscription.setUsername("username");
subscription.setPassword("password");
NotificationLog nlog = subscription.publishNotification(notification, mockUrl, mockSession);
verify(mockHttpConnection).setRequestMethod("POST");
verify(mockHttpConnection).setDoOutput(true);
verify(mockHttpConnection).setRequestProperty("Content-Type", "application/json");
verify(mockHttpConnection)
.setRequestProperty(eq("Authorization"), startsWith("Basic dXNlcm5hbWU6cGFzc3dvcmQ="));
verify(mockHttpConnection).getResponseCode();
verify(mockHttpConnection).disconnect();
assertEquals(NOTIFICATION_ID, nlog.getNotification().getId());
assertEquals(SUBSCRIPTION_ID, nlog.getNotification().getSubscription().getId());
assertEquals(
SUBSCRIBER_ID,
nlog.getNotification().getSubscription().getSubscriber().getId());
}
}
As you can see, we can test the publishNotification by mocking the three collaborators, injecting them into the class under test, and then calling the test method.
Working with the Mockito API
The above example demonstrates the general Mockito test process
- Creating stubs to stand in for collaborators
- Setting expectations on the stubs to do what you want
- Injecting the stubs into the class you plan to test
- Testing the methods in the class under test by invoking its methods, which in turn call methods on the stubs
- Checking the methods work as expected
- Verifying that the methods on the collaborators got invoked the correct number of times, in the correct order
You can use these steps every time you want to use Mockito for replacing collaborators in the class under test, thereby writing true unit tests.
Creating Mocks and Stubs
Mockito has two ways of doing that: using the static mock method or using annotations.
In the example, we added the @Mock annotation to those collaborators that we wanted Mockito to mock:
@Mock
private Session mockSession;
@Mock
private HttpURLConnection mockHttpConnection;
@Mock
private Transaction mockTransaction;
We have three collaborators, so we needed three @Mock annotations on the attributes here.
Setting Expectations
The example mocked the collaborators of Subscription used the methods when and thenReturn to set the expectations on various methods:
when(mockSession.beginTransaction()).thenReturn(mockTransaction);
when(mockHttpConnection.getOutputStream()).thenReturn(new ByteArrayOutputStream());
when(mockUrl.openConnection()).thenReturn(mockHttpConnection);
when(mockHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_ACCEPTED);
The argument to when is the declaration of an invocation of the method you want to call on the stub. The return type connects to the various then methods, like thenReturn, thenThrow, or thenAnswer, which are usually chained to the output.
Verifying Method Calls
After returning from when, you can take advantage of one more capability of Mockito: verifying that the methods on the mocks were called the correct number of times, in the correct order:
verify(mockHttpConnection).setRequestMethod("POST");
verify(mockHttpConnection).setDoOutput(true);
verify(mockHttpConnection).setRequestProperty("Content-Type", "application/json");
verify(mockHttpConnection)
.setRequestProperty(eq("Authorization"), startsWith("Basic dXNlcm5hbWU6cGFzc3dvcmQ="));
verify(mockHttpConnection).getResponseCode();
verify(mockHttpConnection).disconnect();
Running JUnit Tests with Mockito
For JUnit 4, in order to work with the @Mock annotation, add the following @RunWith annotation to your test class:
@RunWith(MockitoJUnitRunner.class)
Alternatively, you can invoke the openMocks method in a setup method tagged with @Before.







