Java 如何编写使用匿名内部类(如PreparedStatementSetter)的类的JUnit测试?
我有一个使用匿名内部类(Java 如何编写使用匿名内部类(如PreparedStatementSetter)的类的JUnit测试?,java,spring,junit,spring-test,spring-test-mvc,Java,Spring,Junit,Spring Test,Spring Test Mvc,我有一个使用匿名内部类(new PreparedStatementSetter())的类,它使用PreparedStatementSetter在查询中设置值,并返回对象的列表 问题是我不确定如何为这种方法编写单元测试。 当我的单元测试到达调用getJdbcTemplate().query(…)的行时,它会跳到行的末尾,discAuditLogList值返回null,单元测试完成时没有任何错误。 当我查看IntelliJ中的代码覆盖率时,所有ps.setString语句从未执行过 ProductL
new PreparedStatementSetter()
)的类,它使用PreparedStatementSetter
在查询中设置值,并返回对象的列表
问题是我不确定如何为这种方法编写单元测试。
当我的单元测试到达调用getJdbcTemplate().query(…)
的行时,它会跳到行的末尾,discAuditLogList
值返回null
,单元测试完成时没有任何错误。
当我查看IntelliJ
中的代码覆盖率时,所有ps.setString
语句从未执行过
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;
}
//这里有一堆setter getter
公共列表getProductLogDetail(RequestDTO RequestDTO)抛出SQLException、DataAccessException{
logger.info(“insideproductlogdao.getProductLogDetail”+requestDTO);
List productLogList=null;
final Map requestParamMap=requestDTO.getParameters();
if(“custom”.equalsIgnoreCase(requestParamMap.get(“recordtype”)){
ProductLogList=getProductCustomDetail(senderFeeSql,requestParamMap);
返回产品日志列表;
}
返回产品日志列表;
}
公共列表getProductCustomDetail(字符串senderFeeSql,
final Map requestParamMap)引发SQLException{
@抑制警告(“未选中”)
List productLogList=getJdbcTemplate().query(senderFeeSql,new PreparedStatementSetter()){
public void setValues(PreparedStatement ps)引发SQLException{
/***************************************************************************************************************/
//以下语句永远不会执行,因为它们位于匿名类(new PreparedStatementSetter()中)
/***************************************************************************************************************/
ps.setString(1,requestParamMap.get(“startFID”);
ps.setString(2,requestParamMap.get(“startFID”);
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”);
}
},新产品CustomRowMapper());
if(null!=productLogList&&(productLogList.size()>0)){
productLogList.get(0.setRecordtype(“自定义”);
productLogList.get(0).setRecordsFetched(productLogList.get(0).getRecordsFetched());
}
返回产品日志列表;
}
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));
}
}
公共类ProductLogDaoTest{
ProductLogDao实例=新的ProductLogDao();
RequestDTO RequestDTO=Mockito.mock(RequestDTO.class);
JdbcTemplate=Mockito.mock(JdbcTemplate.class);
Map requestParamMap=新HashMap();
@以前
public void setUp()引发异常{
setJdbcTemplate(jdbcTemplate);
}
@试验
public void getProductLogDetail_W_Custom()抛出SQLException、DataAccessException{
when(requestDTO.getParameters()).thenReturn(requestParamMap);
requestParamMap.put(“记录类型”、“自定义”);
assertNotNull(instance.getProductLogDetail(requestDTO));
}
}
您模拟了JdbcTemplate
,但没有模拟JdbcTemplate
方法。这就是它返回null的原因
您可以使用某种类型的测试数据库。如果是Spring,您可以使用嵌入式的:。有关测试期间模拟数据库的更多信息,请参阅此问题:
无论哪种方法,您都可以检查您的query()
方法是否使用Mockito的verify()
方法调用。您模拟了JdbcTemplate
,但没有模拟您的JdbcTemplate
方法。这就是它返回null的原因
您可以使用某种类型的测试数据库。如果是Spring,您可以使用嵌入式的:。有关测试期间模拟数据库的更多信息,请参阅此问题:
无论哪种方法,您都可以检查您的query()
方法是否使用Mockito的verify()
方法调用。切勿在依赖对象内部创建如下对象实例:new PreparedStatementSetter()
它很难连接这个类实例,您无法将其更改为模拟。
始终执行以下操作之一:
通过工厂对象方法调用(myBusinessFactoryInstance.createPreparedStatementSetter)创建这些类实例。如果更改工厂,则可以创建模拟
在Spring中,您可以通过构造函数或setter方法注入此依赖项
如果您这样做,您的测试将像一个符咒。永远不要像这样在依赖对象中创建对象实例:new PreparedStatementSetter()
它很难连接这个类实例,您无法将其更改为模拟。
始终执行以下操作之一:
通过工厂对象方法调用(myBusinessFactoryInstance.createPreparedStatementSetter)创建这些类实例。如果更改工厂,则可以创建模拟
在Spring中,您可以通过构造函数或setter方法注入此依赖项
如果您这样做,您的测试将像一个魔咒。谢谢@Bitman,关于如何实施您的建议有什么建议吗?1.调查抽象工厂
和工厂方法
设计模式。2.读一些关于基础弹簧机构的书。写详细的建议太长了。了解SOLID
建模原则,以及Clean code