Issue
i am writing test cases for repository classes were i am not able to cover some of lines in repository classes. i need to achieve 85% of code coverage and its mandatory in my case,Please suggest me something
My actual method
public Map<String, String> getProductFamily(List<String> itmNms) {
Map<String, String> productFamilyMap=new HashMap<String, String>();
try {
NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
String sql = "some query";
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("itmNms", itmNms);
productFamilyMap = namedParameterJdbcTemplate.query(sql, namedParameters, (ResultSet rs) -> {
Map<String, String> productFamily = new HashMap<>();
while (rs.next()) {
productFamily.put(rs.getString("ITEMNAME"), rs.getString("PRODUCTFAMILY"));
}
return productFamily;
});
}catch (Exception e) {
LOGGER.error("Exception in OracleRespository.getProductFamily : {}", e);
}
return productFamilyMap;
}
Test case for above method
@Test
public void getProductFamily() {
List<String> itmNms = new ArrayList<String>();
itmNms.add("A-SPK-NAMED-USER");
oracleRepo.getProductFamily(itmNms);
Map<String, String> mp = new HashMap<String, String>();
Assert.assertNull(mp);
}
By writing above test cases i am able to cover code coverage till line no 6 below lines i am not able to cover due to below statements
productFamilyMap = namedParameterJdbcTemplate.query(sql, namedParameters, (ResultSet rs) ->{}
Can some one suggest how can i achieve code coverage for above method as 100%.
Solution
In cases like that, you need to "manually invoke" the code in lambda. This can be performed with Mockito.doAnswer(...)
functionality of Mockito framework. The example (suitable for Mockito 2+):
Mockito.doAnswer(invocationOnMock -> {
ResultSet resultSet = Mockito.mock(ResultSet.class);
Mockito.when(resultSet.next()).thenReturn(true).thenReturn(false);
Mockito.when(resultSet.getString("ITEMNAME")).thenReturn(...);
Mockito.when(resultSet.getString("PRODUCTFAMILY")).thenReturn(...);
ResultSetExtractor<Map<String, String>> resultSetExtractor =
invocationOnMock.getArgument(2);
return resultSetExtractor.extractData(resultSet);
}).when(namedParameterJdbcTemplate).query(
Mockito.anyString(),
Mockito.any(MapSqlParameterSource.class),
Mockito.any(ResultSetExtractor.class)
);
Then you can verify productFamilyMap
for populated key-value pair.
If you'd still have troubles with it, you can share your code (e.g. via Github) and I'll try to help you with it.
EDIT: Initially, I didn't notice the thing that NamedParameterJdbcTemplate
is created manually with new
, and it's kinda hard to mock it. In this case, it's better to refactor your production code a bit - you can create NamedParameterJdbcTemplate
object as bean (like you probably did with raw JdbcTemplate
) and then inject it into your class (and ofc remove the line where you're creating it with new
). Then the things become trivial.
@Component
public class OracleRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(OracleRepository.class);
@Autowired
private NamedParameterJdbcTemplate namedParameterJdbcTemplate; //created as bean in configuration class
public Map<String, String> getProductFamily(List<String> itmNms) {
Map<String, String> productFamilyMap=new HashMap<String, String>();
try {
String sql = "some query";
MapSqlParameterSource namedParameters = new MapSqlParameterSource();
namedParameters.addValue("itmNms", itmNms);
productFamilyMap = namedParameterJdbcTemplate.query(sql, namedParameters, (ResultSet rs) -> {
Map<String, String> productFamily = new HashMap<>();
while (rs.next()) {
productFamily.put(rs.getString("ITEMNAME"), rs.getString("PRODUCTFAMILY"));
}
return productFamily;
});
}catch (Exception e) {
LOGGER.error("Exception in OracleRespository.getProductFamily : {}", e);
}
return productFamilyMap;
}
}
The test class remains unchanged:
@RunWith(MockitoJUnitRunner.class)
public class OracleRepositoryTest {
@InjectMocks
private OracleRepository oracleRepo;
@Mock
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@Test
public void getProductFamily() {
List<String> itmNms = new ArrayList<>();
itmNms.add("A-SPK-NAMED-USER");
Mockito.doAnswer(invocationOnMock ->{
ResultSet resultSet = Mockito.mock(ResultSet.class);
Mockito.when(resultSet.next()).thenReturn(true).thenReturn(false);
Mockito.when(resultSet.getString("ITEMNAME")).thenReturn("A-SPK-NAMED-USER");
Mockito.when(resultSet.getString("PRODUCTFAMILY")).thenReturn("SPKCLD");
ResultSetExtractor<Map<String, String>> resultSetExtractor =
invocationOnMock.getArgument(2);
return resultSetExtractor.extractData(resultSet);
}).when(namedParameterJdbcTemplate).query(
Mockito.anyString(),
Mockito.any(MapSqlParameterSource.class),
Mockito.any(ResultSetExtractor.class)
);
Map<String, String> productFamilyMap = oracleRepo.getProductFamily(itmNms);
Assert.assertEquals("SPKCLD", productFamilyMap.get("A-SPK-NAMED-USER"));
}
}
Answered By - amseager
Answer Checked By - Pedro (JavaFixing Volunteer)