I am trying to write a Mockito test class to cover some db interaction. The test case I am writing is supposed to return a stub response when the database call is invoked, but it's throwing an NPE trying to actually build a database connection.
Here is the method I am trying to test:
public class AdultDayCenterDBHandler extends DBTemplate implements AppConstants {
Logger logger = LogManager.getLogger(AdultDayCenterDBHandler.class);
public List<FacilityEntity> retrieveAllAdultDayCenterFacilities(FacilitySearchCriteriaInf adcSearchCriteria) throws AdultDayCenterException
{
//Retrieve all the adult day care facilities.
logger.info("[retrieveAllAdultDayCenterFacilities]:[START]");
String sqlQuery = prepareQuery((FacilitySearchCriteriaInf)adcSearchCriteria);
SearchQuery searchQuery = new SearchQuery();
searchQuery.setSqlQuery(sqlQuery);
List<FacilityEntity> adcList;
try {
if(null != logger) logger.debug("Sending Executing SQL query : " + searchQuery.getSqlQuery());
adcList = (List<FacilityEntity>) callDB((SearchQuery)searchQuery);
} catch (DBException e) {
throw new AdultDayCenterException("Error ocurred in AdultDayCenterDBHandler while calling DB",e);
}
logger.info("[retrieveAllAdultDayCenterFacilities]:[END]");
return adcList;
}
And here is the test case:
@ExtendWith(MockitoExtension.class)
public class AdultDayCenterDBHandlerTest {
@Mock
private DBTemplate dbTemplate;
@Mock
private DBUtil dbUtil;
@InjectMocks
private AdultDayCenterDBHandler dbHandler;
@BeforeEach
public void setUp() {
assertNotNull(dbUtil);
assertNotNull(dbTemplate);
}
@Test
public void testRetrieveAllAdultDayCenterFacilities() throws Exception {
//Setup
List<FacilityEntity> facilityList = generateStubData();
List<FacilityEntity> responseFromTest = null;
ADCSearchCriteria adcSearchCriteria = generateSearchCriteria();
Mockito.when(dbTemplate.callDB(any(SearchQuery.class))).thenReturn(facilityList);
//Get Result Set
responseFromTest = dbHandler.retrieveAllAdultDayCenterFacilities(adcSearchCriteria);
//Assertions
assertNotNull(responseFromTest);
assertEquals(responseFromTest.get(0).getFacilityName(),facilityList.get(0).getFacilityName());
}
private List<FacilityEntity> generateStubData() {
List<FacilityEntity> response = new ArrayList<FacilityEntity>();
FacilityEntity entity = new FacilityEntity();
entity.setFacilityName("Test Facility 1");
entity.setLicenseId(123456);
entity.setLocationAddressStreetNumber("1234");
entity.setLocationAddressLine1("Main Street");
entity.setLocationAddressCity("Mechanicsville");
entity.setLocationAddressStateName("VA");
entity.setLocationAddressZipCode("23116");
entity.setLocationCountyFips("51085");
entity.setLocationCountyDesc("Hanover");
entity.setAdministratorFirstName("Jane");
entity.setAdministratorSurname("Doe");
entity.setAdministratorTitle("Administrator");
entity.setBusinessPhoneNumber("804-301-2011");
entity.setClientCode("2101");
response.add(entity);
return response;
}
private ADCSearchCriteria generateSearchCriteria() {
ADCSearchCriteria criteria = new ADCSearchCriteria();
criteria.setFacilityName("Test Facility 1");
criteria.setProgramCode(PROGRAM_CODES.ADC_F);
return criteria;
}
}
My guess is I need to mock an additional object, but I'm not sure why this line:
Mockito.when(dbTemplate.callDB(any(SearchQuery.class))).thenReturn(facilityList);
//Get Result Set
responseFromTest = dbHandler.retrieveAllAdultDayCenterFacilities(adcSearchCriteria);
isn't returning the mock object I defined. It's throwing an NPE trying to instantiate DBUtil.
I may be reading this incorrectly, but you mock an instance of DBTemplate
. However, the class you're injecting mocks in doesn't contain any DBTemplate
, it extends DBTemplate
. In other words, your mocked object never goes into the AdultDayCenterDBHandler
instance.
If you want to mock the callDB
call of the AdultDayCenterDBHandler
instance, you need to create a spy. You can then mock the method call. However, you can't use "when(...).then(...)" because that will already call the actual method. Use the following instead:
Mockito.doReturn(facilityList).when(dbHandler).callDB(any(SearchQuery.class));
This way, the method call (callDB
) is performed on an object representing the spied object, not the spied object itself.