Unit Testing Using Mockito and PowerMock
We take a look at these two great testing frameworks to see how they can help with a myriad of unit testing use cases.
Join the DZone community and get the full member experience.
Join For FreeHey all, today I will talk about how we can mock and spy on methods for testing purposes using Mochito and PowerMock.
First of all, we need to set up MockitoAnntations
before running our tests.
We just use the @Before
annotation to run our initializations before the test runs.
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
when...thenReturn
and when...thenAnswer
Patterns
So let's start with mocking a service method which has to return an object. In order to do that, we can use the when...thenReturn
or when...thenAnswer
patterns
In order to enable Mock and Spy injections, the service, which will inject them, has to be defined with the @InjectMock
annotation.
@InjectMocks
BatchServiceImpl batchServiceImpl
Mocked services are defined with the@Mock
annotation
@Mock
ControlService controlService;
@Mock
PersistDataService persistDataService;
@Mock
FetchDataService fetchDataService;
With the help of the when... thenReturn
pattern we can stub our method execution. See the example below
@Test
public void test_001()
{
FetchDataResponse fetchDataResponse=new FetchDataResponse();
fetchDataResponse.setResultCode(-1);
when(fetchDataService.fetchSomeDataWithResponse(Mockito.any(FetchDataRequest.class)))
.thenReturn(fetchDataResponse);
BaseResponse baseResponse = batchServiceImpl.executeBatchServices();
if(baseResponse.getResultCode()==-1)
Assert.assertTrue(true);
else
Assert.assertTrue(false);
}
We can also use the when...thenAnswer
pattern for these kinds of cases. One difference between when... thenReturn
and when... thenAnswer
is that with when...thenAnswer
we can vary the value returned every time a stubbed method is executed. See this code sample:
when(fetchDataService.fetchSomeDataWithResponse(Mockito.any(FetchDataRequest.class)))
.thenAnswer(invocationOnMock -> {
FetchDataResponse fetchDataResponse=new FetchDataResponse();
fetchDataResponse.setRandomNumber(UUID.randomUUID().toString());
fetchDataResponse.setResultCode(-1);
return fetchDataResponse;
});
}
The second difference is that you can use your inputs inside your stubbed method. See the below example:
when(fetchDataService.fetchSomeDataWithResponse(Mockito.any(FetchDataRequest.class)))
.thenAnswer(invocationOnMock -> {
Object[] arguments = invocationOnMock.getArguments();
FetchDataResponse fetchDataResponse=new FetchDataResponse();
FetchDataRequest request = (FetchDataRequest)arguments[0];
if(request.getProcessStatus()=.INITIAL.getStatus())
fetchDataResponse.setResultCode(-2);
else
fetchDataResponse.setResultCode(-1);
return fetchDataResponse;
});
Verify Method Executions and Evaluate the Inputs
If you want to evaluate your inputs, you have to use Mochito.verify
and ArgumentCaptor
. See the example code below:
@Test
public void test_003()
{
when(fetchDataService.fetchSomeDataWithResponse(Mockito.any(FetchDataRequest.class)))
.thenAnswer(invocationOnMock -> {
FetchDataResponse fetchDataResponse=new FetchDataResponse();
fetchDataResponse.setResultCode(-1);
return fetchDataResponse;
});
batchServiceImpl.executeBatchServices();
ArgumentCaptor<FetchDataRequest> fetchDataRequestCaptor = ArgumentCaptor.forClass(FetchDataRequest.class);
Mockito.verify(fetchDataService).fetchSomeDataWithResponse(fetchDataRequestCaptor.capture());
FetchDataRequest inputRequest = fetchDataRequestCaptor.getValue();
if (inputRequest.getRowSize() != 1000)
Assert.assertTrue(false);
else if (inputRequest.getProcessStatus() != ProcessStatusEnum.INITIAL.getStatus())
Assert.assertTrue(false);
else
Assert.assertTrue(true);
}
While verifying your execution via Mockito.verify
, you can also check how many times your method was executed by using Mockito.times
or Mockito.never
.
Mockito.verify(fetchDataService,Mockito.times(1)).fetchSomeDataWithResponse(fetchDataRequestCaptor.capture());
Mocking Void Methods
If you need to mock void methods, you can use Mockito.doAnswer
. See the example below:
Mockito.doAnswer((i) -> {
return null;
}).when(persistDataService).persist(Mockito.any(FetchDataRequest.class));
Let's say that you have a void method and you need to set its value to your input object. You can do so like this:
Mockito.doAnswer((i) -> {
FetchDataDto fetchDataDto=new FetchDataDto();
fetchDataDto.setId(1l);
fetchDataDto.setName("Mike");
fetchDataDto.setSurName("Howard");
fetchDataDto.setAddressInfo("Chicago");
List <FetchDataDto> fetchDataDtoList=new ArrayList<>();
fetchDataDtoList.add(fetchDataDto);
((FetchDataRequest)i.getArgument(0)).setFetchDataDtoList(fetchDataDtoList);
return null;
}).when(fetchDataService).fetchSomeData(Mockito.any(FetchDataRequest.class));
Throwing Exceptions in Mock Methods
If your real method is throwing an exception in some cases, and if you need to test the business logic after the exception occurs, you can mock the method like this:
Mockito.doThrow(new TraceServiceException(ErrorTypeEnum.BOOSTER_EXCEPTION.getErrorCode(),"Error Occured")).when(actionHandlerService).dispatchData(any(DailyFeedBackRequest.class));
Spy on Methods
Sometimes you need to run the real method, verify the execution, and evaluate the inputs. You can do partial mocking for this by using the Spy
functionality .
You can define an interface and define spy
for its implementation in the initialization phase and verify the execution and evaluate of the inputs in the test code.
@Before
public void setUp() throws Exception {
persisDataService = spy(new PersistDataServiceImpl());
MockitoAnnotations.initMocks(this);
}
@Test
public void test_011() throws Exception {
Mockito.doAnswer((i) -> {
FetchDataDto fetchDataDto=new FetchDataDto();
fetchDataDto.setId(1l);
fetchDataDto.setName("Mike");
fetchDataDto.setSurName("Howard");
fetchDataDto.setAddressInfo("Chicago");
List <FetchDataDto> fetchDataDtoList=new ArrayList<>();
fetchDataDtoList.add(fetchDataDto);
((FetchDataRequest)i.getArgument(0)).setFetchDataDtoList(fetchDataDtoList);
return null;
}).when(fetchDataService).fetchSomeData(Mockito.any(FetchDataRequest.class));
when(controlService.makeSomeCheck(Mockito.any(FetchDataRequest.class)))
.thenAnswer(invocationOnMock -> {
BaseResponse baseResponse=new BaseResponse();
baseResponse.setResultCode(0);
return baseResponse;
});
batchServiceImpl.executeBatchServices();
verify(persisDataService).spyMethod(any(FetchDataRequest.class));
}
Mocking Private Methods
If your project contains private methods to test, you can’t use Mockito as it does not mock private methods. On the other hand, we can use the Powermock framework which provides us this functionality with Whitebox.invokeMethod
.
@Test
public void test_009()
{
try {
Object obj = Whitebox.invokeMethod(batchServiceImpl, "makeTheChecks", any(FetchDataRequest.class));
BaseResponse baseResponse = (BaseResponse) obj;
if (baseResponse.getResultCode() == 0)
Assert.assertTrue(true);
} catch (Exception ex) {
Assert.assertTrue(false);
}
}
Opinions expressed by DZone contributors are their own.
Comments