This page is about Mockito.
For JUnit 5, see > https://sites.google.com/site/pawneecity/java-development/test-w-junit5-java
OpenMocks, clean-up, etc (makes unnecessary MockitoAnnotations.openMocks)
JUnit 5 > @ExtendWith(MockitoExtension.class)
JUnit 4 > @RunWith(MockitoJUnitRunner.class)
Mockito JDK
5 >=11
4 <=8
2 =6
https://www.infoq.com/news/2023/01/mockito-5/
package edu.cou.myapp;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import lombok.extern.slf4j.Slf4j;
/**
*/
@Slf4j
public class TestMockingIssueAnswer implements Answer<Object> {
private static final Gson GSON = new Gson();
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
String msg = buildMockingIssueMessage(invocation);
//
if (log.isDebugEnabled()) {
// Not usually needed, since the WrongMethodTypeException message is always printed
log.info(msg);
}
throw new java.lang.invoke.WrongMethodTypeException(msg);
}
/*-
* It build a mocking issue message.
* @param invocation
* @return The mocking issue message
*/
private String buildMockingIssueMessage(InvocationOnMock invocation) {
String msg;
if (invocation == null) {
msg = "********MOCKING:Probably method mocking failed********";
} else if (invocation.getMethod() == null) {
Object mock = invocation.getMock();
msg = String.format("********MOCKING:Not stubbed on %s********", serializeOrClassName(mock));
} else {
Object[] args = invocation.getArguments();
Object mock = invocation.getMock();
msg = String.format(
"********MOCKING:Method %s not stubbed on %s, called with arguments %s********",
invocation.getMethod().getName(), serializeOrClassName(mock), GSON.toJson(args));
}
return msg;
}
/*-
* Serialize mock
* @param mock Either the serialized object if possible, or its class name
*/
private String serializeOrClassName(final Object mock) {
String ret;
try {
ret = GSON.toJson(mock);
} catch (UnsupportedOperationException e) {
// DOC. 'mock' is not serializale, see: https://stackoverflow.com/a/41937577/1323562
ret = mock.getClass().getName();
}
return ret;
}
}
Used for creating and injecting mocked instances. We don't create real objects, rather ask mockito to create a mock for the class.
Spring Boot @MockBean is similar to @Mock but with Spring support:
If the test doesn't need any dependencies from the Spring Boot container then @Mock shall be used. It's fast and favors the isolation of the tested component
If the test needs to rely on the Spring Boot container and we want also to add or mock one of the container beans then @MockBean is the preferred way to add mocks
For instantiating a class, via its default constructor, and spy on that real object.
Note: For spying any object, use instead: Mockito.spy(theObject).
A spy helps to call all the normal methods of the object while still tracking every interaction, just as we would with a mock.
@SpyBean can be used to apply Mockito spies to a Spring ApplicationContext.
Used for creating and ArgumentCaptor instance which is used to capture method argument values for further assertions. Mockito verifies argument values using the equals() method of argument class.
Needed for creating the object of the class to be tested and then insert its dependencies (both @Mock and @Spy).
Warning: If an injection is not provided by either @Mock or @Spy then it'd be null.
Allows to create a mock object of a class or an interface.
Used for verifying that a method with expected arguments is invoked the specified number of times.
any(), any(Object.class), any(Object[].class) - the array one allows to match any number of arguments of the specified type
anyInt()
anyString()
aryEq - equality of arrays
eq() - specific value
isNull() - match null. Only Java >= 8 & Mockito >= 2
same(obj) - checks that the argument refers to the same instance as obj, such that arg == obj
Get a mock of the class
log.info("#### Mocking myclassTest");
final MyClass c = Mockito.mock(MyClass.class,
new TestMockingIssueAnswer());
Mock the method
log.info("#### Mocking myclassTest.getThirdsByIdpList");
doAnswer(i -> fakeResponseGetThirdsByIdpList( (ArrayOfInt) i.getArguments()[0] )).when(c).getThirdsByIdpList(Mockito.any());
The lambda function used in the method mock
private ArrayOfThirdReducedVO fakeResponseGetThirdsByIdpList(ArrayOfInt codes) {
List<Integer> ins = codes.getInt();
ArrayOfThirdReducedVO ret = new ArrayOfThirdReducedVO();
for (Integer idpx : ins) {
ThirdReducedVO trx = new ThirdReducedVO();
trx.setAttribute1("A1-"+idpx);
trx.setAttribute2("A2-"+idpx);
ret.getThirdReducedVO().add(trx);
}
return ret;
}
Sample doNothing:
doNothing().when(c).setFinalWork(Mockito.any(), Mockito.any(), Mockito.any());
Sample docCallRealMethod:
doCallRealMethod().when(environmentHelperMock).getEnvironmentMap();
Sample doReturn:
doReturn("Bearer f4k3").when(this.httpServletReqMock).getHeader("Authorization");
NotifService.java
@AllArgsConstructor(onConstructor_ = { @Inject })
@Slf4j
@Service
public class NotifService {
private NotifEnrollmentVeteranRepo notifEnrollmentVeteranRepo;
private NotifMilestoneService notifMilestoneService;
...
}
NotifServiceTest.java
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = { App.class })
class NotifServiceTest {
/*- Need to be injected into notifService */
@Spy
private NotifEnrollmentVeteranRepo notifEnrollmentVeteranRepo;
@Mock
private NotifMilestoneService notifMilestoneService;
@Spy
@InjectMocks
private NotifService notifService;
private AutoCloseable closeable;
@BeforeEach
void beforeEach() {
this.closeable = MockitoAnnotations.openMocks(this);
}
@AfterEach
void afterEach() throws Exception {
this.closeable.close();
}
@Test
public void startNotifTest() {
Mockito.doReturn(getDummyCurriculumConfigList()).when(curriculumDurationConfigService)
.findAll();
//
Set<AcademicRecord> ars = new HashSet<>();
AcademicRecord iniGatCodeKO = getDummyAcademicRecord(1L, "32423", "20184", null, null, null);
ars.add(iniGatCodeKO);
AcademicRecord opCalCodeKO = getDummyAcademicRecord(2L, "23", "20201", null, null, null);
ars.add(opCalCodeKO);
opCalCodeKO = getDummyAcademicRecord(3L, "8", null, null, null, null);
ars.add(opCalCodeKO);
AcademicRecord academicRecordOK = getDummyAcademicRecord(4L, "8", "20181", null, null, null);
academicRecordOK.setPersonCode(123L);
ars.add(academicRecordOK);
AcademicRecord alreadyHasNotif = getDummyAcademicRecord(5L, "8", "20181", null, null, null);
ars.add(alreadyHasNotif);
Mockito.doReturn(ars).when(academicManagementService)
.getAcademicRecordsInAorCAndNotIdentityValidated();
// Enrollments not cancelled for ar=4
Set<Enrollment> es4 = new HashSet<>();
es4.add(new Enrollment(new EnrollmentId(4L, "20181", 10L)));
Mockito.doReturn(es4).when(academicManagementService).getEnrollmentsNotCanceled(4L);
//
this.notifService.startNotificationVeterans();
Mockito.verify(notifService).notifAndPersistVeteran2(123L, "1", new EnrollmentId(4L, "20181",
10L));
}
}
@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = { App.class })
class CalendarControllerTest {
@MockBean
private CalendarRepo calendarRepo;
@Inject
private CalendarController calendarController;
private AutoCloseable closeable;
@BeforeEach
void beforeEach() {
this.closeable = MockitoAnnotations.openMocks(this);
}
@AfterEach
void afterEach() throws Exception {
this.closeable.close();
}
/** */
@Test
void getCalendarsTest() {
List<Object[]> objectList = new ArrayList<>();
Object[] ob = new Object[2];
ob[0] = "20221";
ob[1] = "2022/23-1";
objectList.add(ob);
doReturn(objectList).when(calendarRepo).getCalendarDetail(Mockito.anyString(), Mockito.anyString());
ResponseEntity<Set<CalendarDetail>> res = calendarController.getCalendar("en", "20212");
assertNotNull(res);
var body = res.getBody();
assertNotNull(res.getBody());
assertEquals(1, body.size());
var elem0 = body.iterator().next();
assertEquals("20221", elem0.getId());
assertEquals("2022/23-1", elem0.getNameShort());
}
}
@Mock
HashMap<String, Integer> hashMap;
@Captor
ArgumentCaptor<String> keyCaptor;
@Captor
ArgumentCaptor<Integer> valueCaptor;
@Test
public void saveTest()
{
hashMap.put("A", 10);
Mockito.verify(hashMap).put(keyCaptor.capture(), valueCaptor.capture());
assertEquals("A", keyCaptor.getValue());
assertEquals(new Integer(10), valueCaptor.getValue());
}
Including openMocks, @BeforeAll, @AfterAll, @BeforeEach & @AfterEach.
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.Mockito.doReturn;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.Optional;
import org.apache.commons.io.input.CharSequenceInputStream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
/**
*/
class SerializationUtilsTest {
private static class SampleJson {
@SuppressWarnings("unused")
String myProperty;
}
@Mock
private HttpURLConnection httpURLConnection;
private AutoCloseable closeable;
@BeforeAll
private static void beforeAll() {
// sample
}
@AfterAll
private static void afterAll() {
// sample
}
@BeforeEach
void beforeEach() {
this.closeable = MockitoAnnotations.openMocks(this);
}
@AfterEach
void afterEach() throws Exception {
this.closeable.close();
}
/**
* @throws Exception
*/
@Test
void jsonHttpTest() throws Exception {
InputStream is = new CharSequenceInputStream("{\"myProperty\":\"My value\"}", "UTF-8");
doReturn(is).when(this.httpURLConnection).getInputStream();
Optional<SampleJson> res = SerializationUtils.getObjectFromJSON(this.httpURLConnection,
SampleJson.class);
assertNotNull(res);
}
}
@Test
void userinfoHttpClientErrorExceptionTest() {
// mock
doThrow(HttpClientErrorException.class).when(this.restTemplate).exchange(Mockito.anyString(),
Mockito.any(), Mockito.any(), Mockito.eq(RespRestUserinfoServiceDTO.class));
//
Assertions.assertThrows(IllegalStateException.class, () -> {
this.oauthClientHelper.userinfo("Bearer " + TestK.PERSON_SAINTS_OT);
});
}
@Test
void obtainHttpErrorStreamBodyTest() throws IOException {
HttpURLConnection connection = mock(HttpURLConnection.class);
InputStream errorInputStream = new ByteArrayInputStream("ErrorContent".getBytes());
doReturn(errorInputStream).when(connection).getErrorStream();
assertEquals("ErrorContent", Userinfo.obtainHttpErrorStreamBody(connection));
}