Search code examples
javaspring-bootjunitjunit4jacoco

Junit How to mock namedParameterJdbcTemplate.query(" ", parameters,(ResultSet rs))


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"));
        }
    }