0

I have the following class that uses an anonymous inner class (new PreparedStatementSetter()) to set values in the query using a PreparedStatementSetter and returns a List of object.

The problem is that I am not sure how to write unit test for this kind of method. As soon as my unit test reaches the line where it calls getJdbcTemplate().query(......) it jumps to the end of line and discAuditLogList value returns null and unit test finishes without any errors. When I look at the code coverage in IntelliJ all the ps.setString statements never got executed.

ProductLogDao.java

//bunch of setter getters here

public List<ProductLogDTO> getProductLogDetail(RequestDTO requestDTO) throws SQLException, DataAccessException {
    logger.info("Inside ProductLogDao.getProductLogDetail" + requestDTO);
    List<ProductLogDTO> productLogList = null;
    final Map<String, String> requestParamMap = requestDTO.getParameters();
    if ("custom".equalsIgnoreCase(requestParamMap.get("recordtype"))) {
        ProductLogList = getProductCustomDetail(senderFeeSql, requestParamMap);
        return ProductLogList;
    }
    return productLogList;
}


public List<ProductLogDTO> getProductCustomDetail(String senderFeeSql,
                                                          final Map<String, String> requestParamMap) throws SQLException {
    @SuppressWarnings("unchecked")
    List<ProductLogDTO> productLogList = getJdbcTemplate().query(senderFeeSql, new PreparedStatementSetter() {
        public void setValues(PreparedStatement ps) throws SQLException {
            /***************************************************************************************************************/
            //FOLLOWING STATMENTS NEVER GET EXECUTED BECAUSE THEY ARE WITHIN ANONYMOUS CLASS (new PreparedStatementSetter())
            /***************************************************************************************************************/
            ps.setString(1, requestParamMap.get("startDfId"));
            ps.setString(2, requestParamMap.get("startDfId"));
            ps.setString(3, requestParamMap.get("chanelId"));
            ps.setString(4, requestParamMap.get("chanelId"));
            ps.setString(5, requestParamMap.get("fromDateTime"));
            ps.setString(6, requestParamMap.get("toDateTime"));
            ps.setString(7, requestParamMap.get("fromDateTime"));
            ps.setString(8, requestParamMap.get("toDateTime"));
        }
    }, new ProductCustomRowMapper());

    if (null != productLogList && (productLogList.size() > 0)) {
        productLogList.get(0).setRecordtype("custom");
        productLogList.get(0).setRecordsFetched(productLogList.get(0).getRecordsFetched());
    }
    return productLogList;
}

ProductLogDaoTest.java

public class ProductLogDaoTest {

    ProductLogDao instance = new ProductLogDao();
    RequestDTO requestDTO = Mockito.mock(RequestDTO.class);
    JdbcTemplate jdbcTemplate = Mockito.mock(JdbcTemplate.class);
    Map<String, String> requestParamMap = new HashMap<>();

    @Before
    public void setUp() throws Exception {
        instance.setJdbcTemplate(jdbcTemplate);
    }

    @Test
    public void getProductLogDetail_W_Custom() throws SQLException, DataAccessException {
        when(requestDTO.getParameters()).thenReturn(requestParamMap);
        requestParamMap.put("recordtype", "custom");
        assertNotNull(instance.getProductLogDetail(requestDTO));
    }

}
Nital
  • 5,784
  • 26
  • 103
  • 195

2 Answers2

2

Never create an object instance inside in the dependent object like this: new PreparedStatementSetter() It wires this class instance hardly and you unable to change it to a mock. Always do one of these:

  1. Create these class instances by a factory object method call (myBusinessFactoryInstance.createPreparedStatementSetter). Than you can create a mock if you change the factory.

  2. In Spring you can inject this dependency by constructor or setter method.

If you do so your testing will be like a charm.

The Bitman
  • 1,279
  • 1
  • 11
  • 25
  • Thanks @The Bitman, any pointers on how to implement your suggestions? – Nital Jul 23 '19 at 02:59
  • 1
    1., Investigate the `Abstract Factory` and the `Factory method` design patterns. 2., Read some books about base Spring mechanisms. It is too long to write detailed suggestions. Learn about `SOLID` modelling principles, the `Clean Code`, etc. Rober Cecil Martin as an author is a very good source of knowledge. – The Bitman Jul 25 '19 at 09:15
0

You have mocked JdbcTemplate, but haven't mocked your JdbcTemplate methods. That's why it returns null.

You can use some kind of test database. In case of Spring you can use embedded ones: https://docs.spring.io/spring/docs/3.0.0.M4/spring-framework-reference/html/ch12s08.html. Please refer to this question for more information about simulating database during tests: How to simulate a DB for testing (Java)?

Either way you can check whether or not your query() method was called with Mockito's verify() method.

Sergei Podlipaev
  • 1,331
  • 1
  • 14
  • 34