Skip to content

Ferdinand Agyei-Yeboah

Junit and Mockito

March 16, 2022

Basic Example

There are three basic phases to writing unit tests. Mocking, Execution, Verification. Each of the steps are shown in the example below.

@RunWith(MockitoJunitRunner.class)
public class ControllerTest {
@Mock
AppService service;
@Mock
UserRepository userRepo;
@InjectMocks
AppController controller;
@Test
public void testRetrieveMessage(){
//Data prep
String mockText = "hello!";
RetrieveMessagesResponse expected = new RetrieveMessagesResponse(text);
expected.setSuccess("SUCCEEDED");
String input = "this is my message";
//Mock - mock any internal dependencies that are decorated with @Mock
Mockito.when(service.getMessage(any(String.class))).thenReturn(mockText);
Mockito.when(userRepo.findById(any(Long.class))).thenReturn(1L);
//Execution - execution the method under test.
RetrieveMessagesResponse actual = controller.retrieveMessage(input);
//Verification
assertEquals(expected, actual);
}
}

Exception testing example

To test exception handling, you can mock a thrown exception and then catch the exception (more flexibility to do verification) or just tell the test to expect the exception (less flexibility). Both ways are shown below.

@RunWith(MockitoJunitRunner.class)
public class ControllerTest {
@Mock
AppService service;
@Mock
UserRepository userRepo;
@InjectMocks
AppController controller;
@Test
public void testExceptionFirstWay(){
//Data prep
String mockText = "hello!";
String input = "this is my message";
//Mock - force exception to be thrown
Mockito.when(service.getMessage(any(String.class))).thenThrow(new ServerException("can't find message"));
//Execution and verification
try {
RetrieveMessagesResponse actual = controller.retrieveMessage(input);
Assertions.fail("Expected server exception to be thrown, but was not").
}
catch (ServerException ex){
assertEquals("can't find message", ex.getErrorMessage());
}
}
@Test(expected = ServerException.class)
public void testExceptionSecondWay(){
//Data prep
String mockText = "hello!";
String input = "this is my message";
//Mock - force exception to be thrown
Mockito.when(service.getMessage(any(String.class))).thenThrow(new ServerException("can't find message"));
//Execution - will throw ServerException and is expected so test will pass
RetrieveMessagesResponse actual = controller.retrieveMessage(input);
}
}

Other things

Setting internal fields or testing private methods
To set internal fields, you can use Spring ReflectionTestUtils.setField(). This assumes you are using Spring, else probably can use power mock.

To call private methods, you can use powerMock Whitebox.invokeMethod().

PowerMock

ThenAnswer
When you want your mocking response to differ based on the arguments passed, you can use .thenAnswer to return the mock response.

Mockito.when(service.retrieveMessage(any(String.class), any(Integer.class))).thenAnswer(invocation -> {
RetriveMessageResponse response = new RetriveMessageResponse();
response.setText(invocation.getArgument(0)); //Set the first argument as text response.
return response;
})

Number of Times
You can verify the number of times a method was called. In this case, checking service.retrieveProduct() got called twice.

Mockito.verify(service, times(2)).retrieveProduct(anyString());

Throwing Spring’s DataAccessException
DataAccessException is an abstract class meaning you can’t instantiate it directly. You find a subclass that can be instantiated or an anonymous class.

.thenThrow(throw new DataAccessException("failed") {})

Using a real object mapper - since most times it doesn’t need to be mocked

@Mock
ObjectMapper mapper;
Mockito.when(mapper.createObjectNode()).thenReturn(new ObjectMapper().createObjectNode());

Software Engineering Tutorials & Best Practices