I have layered architecture in the spring boot project like Controller -> Service -> Dao. I have to write unit test cases to check all functionality. I want to write unit test cases for service layer and Dao layer. Service layer internally calls 3 DAO methods.
Currently, I am trying to write test cases for service layer and its internally calling Dao methods but its giving null pointer exception.
My Testing code is as below. After executing this test case, I am getting null pointer exception on 'namedParameterJdbcTemplate.queryForObject(existingUtQuery, namedParameters, GeneratorRowMapper)' in GeneratorRepository Dao class. I have initialized 'generatorRepository = new GeneratorRepository() and uTService = new UTService()' in Response1 test method of test class otherwise it give null pointer exception.
@ExtendWith(MockitoExtension.class)
public class GenerationApplicationTests {
@InjectMocks
private GeneratorRepository generatorRepository;
@Mock
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Autowired
private UTService uTService;
@Test
public void Response1() throws Exception {
generatorRepository = new GeneratorRepository();
uTService = new UTService();
Request request = new Request("12345678", "F", 0, "A");
Generator generator = new Generator("12345678.F","3er45FGTYH");
System.out.println("utService : "+utService);
when(generatorRepository.findExisting(request)).thenReturn(generator);
Response response = uTService.getUT(Request);
assertEquals("12345678.F", response.getValue());
assertEquals("3er45FGTYH", response.getPre());
}
}
Service Class
@Service
public class UTService {
@Autowired
private GeneratorRepository generatorDAO;
@Autowired
private TableFunctionRepository tableFunctionRepository;
public Response getUT(Request request) throws UTNotFoundException {
Response response = new Response();
Generator existing = new Generator();
TableFunction tableData = new TableFunction();
Generator new = new Generator();
Reasons exclusionInclusion = null;
existing = generatorDAO.findExisting(request);
if (existing != null) {
response.setResponse(existing);
return response;
}
tableData = tableFunctionRepository.callTableValuedFunction(request);
if (tableData == null) {
String exceptionMessage = Request + " not found in database";
throw new UTNotFoundException(exceptionMessage);
} else {
new.setInfo(request.getId(), request.getSubId(), request.getRevisionNo(), request.getState());
exclusionInclusion = checkExclusionInclusionCriteria(tableData);
new.setExclusionInclusionReasonId(exclusionInclusion.getReasonCode());
new = generateUT(tableData, exclusionInclusion, new);
response.setResponse(new);
generatorDAO.saveUT(new);
}
log.info("finished getUT");
return response;
}
}
Dao Classes
@Repository
public class GeneratorRepository
{
@Value("${sql.saveutiQuery}")
private String saveUTQuery;
@Value("${sql.existingUtiQuery}")
private String existingUtQuery;
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Autowired
private BeanPropertyRowMapper<Generator> generatorRowMapper;
public int saveUT(Generator generator) {
int rowsAffected = 0;
try {
SqlParameterSource paramSource = new BeanPropertySqlParameterSource(generator);
rowsAffected = namedParameterJdbcTemplate.update(saveUTQuery, paramSource);
} catch(Exception e) {
throw e;
}
return rowsAffected;
}
public Generator findExistingUT(Request request) {
Generator ut = new Generator();
try {
SqlParameterSource namedParameters = new MapSqlParameterSource()
.addValue("No", request.getId(), Types.VARCHAR)
.addValue("Sub", request.getSubId(), Types.VARCHAR)
.addValue("Revision", request.getRevision(), Types.INTEGER)
.addValue("state", request.getState(), Types.VARCHAR);
ut = namedParameterJdbcTemplate.queryForObject(existingUtQuery, namedParameters, GeneratorRowMapper);
} catch (Exception e) {
throw e;
}
return ut;
}
}
@Repository
public class TableFunctionRepository {
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Autowired
private BeanPropertyRowMapper<TableFunction> tableFunctionRowMapper;
@Value("${sql.DetailsQuery}")
private String tableDetailsQuery;
public TableFunction callTableValuedFunction(Request request) {
TableFunction tableDetails = new TableFunction();
try {
SqlParameterSource namedParameters = new MapSqlParameterSource()
.addValue("No", request.getId(), Types.VARCHAR)
.addValue("Sub", request.getSub(), Types.VARCHAR)
.addValue("Revision", request.getRevision(), Types.INTEGER)
.addValue("state", request.getState(), Types.VARCHAR);
tableDetails = namedParameterJdbcTemplate.queryForObject(tableDetailsQuery, namedParameters, tableFunctionRowMapper);
} catch (Exception e) {
throw e;
}
return tableDetails;
}
}
What approach should I follow to write test cases using junit and mockito to cover both service and Dao layer.
First of all, When you have @autowired
variables it means that you need to @mock
them if you want to get mocked object.
Then if you test the Service class then you need to use @InjectMocks
for this service. It means that you are creating a mocked service for testing and injecting to him all mocks that you mocked with @mock
annotation or with another way.
Here updated version of your test:
@ExtendWith(MockitoExtension.class)
public class UTServiceTest {
@InjectMocks
private UTService uTService;
@Mock
private GeneratorRepository generatorRepository;
@Mock
private TableFunctionRepository tableFunctionRepository;
@Test
public void testGetUT_whenExistingGeneratorFound_returnResponse() throws UTNotFoundException {
// Arrange
Request request = new Request("12345678", "F", 0, "A");
Generator existingGenerator = new Generator("12345678.F", "3er45FGTYH");
Response expectedResponse = new Response(existingGenerator);
// Mock generatorRepository to return an existing generator for the given request
when(generatorRepository.findExisting(request)).thenReturn(existingGenerator);
// Act
Response actualResponse = uTService.getUT(request);
// Assert
assertEquals(expectedResponse, actualResponse);
}
And you can test your exception throwing
@Test
public void testGetUT_whenTableDataNotFound_throwUTNotFoundException() throws UTNotFoundException {
Request request = new Request("12345678", "F", 0, "A");
when(tableFunctionRepository.callTableValuedFunction(request)).thenReturn(null);
assertThrows(UTNotFoundException.class, () -> uTService.getUT(request));
}
Also, you can test the one more case when all is passing by adding this lines to first test case but write 3rd test for it:
when(generatorRepository.findExisting(request)).thenReturn(null);
// Mock tableFunctionRepository to return tableData for the given request
when(tableFunctionRepository.callTableValuedFunction(request)).thenReturn(tableData);
// Mock the generateUT method to return the expectedGenerator
when(uTService.generateUT(tableData, exclusionInclusion, any(Generator.class)))