[英]Write unit test for jdbcTemplate.batchUpdate() method
我有 jdbcTemplate 代码,我正在尝试在其上编写单元测试用例。
public void updateData(List<Student> students, String status){
try{jdbcTemplate.batchUpdate("update query", new BatchPreparedStatementSetter(){
@Override
public int getBatchSize()
return students.size();
}
@Override
public void setValues(PreparedStatement ps int i){
Student student = students.get(i);
ps.setInt(1, student.getRollNo());
ps.setString(2, student.getName());
}
});
}catch(Exception ex){}
}
但问题是我无法涵盖完整的代码。 我能够覆盖到:
try{jdbcTemplate.batchUpdate("更新查询", new BatchPreparedStatementSetter(){
测试代码片段
@Test
public void testMe(){
List<Student> students = new ArrayList<>();
mockedObject.updateData(students ,"success");
}
请帮忙。
这里的困难在于包含您要测试的主要逻辑的new BatchPreparedStatementSetter(){...}
实例是updateData()
方法的实现细节。 它仅在测试方法内部定义。
要解决这个问题,您有两种经典方法:
@DataJpaTest
(最终是部分集成测试)的测试切片,这将更简单,因为您将能够测试副作用并且当您在数据库中断言 state 而不是代码中的语句时也更有帮助。BatchPreparedStatementSetter
实例创建。例如:
@Service
class BatchPreparedStatementFactory{
public BatchPreparedStatementSetter ofStudentsBatchPreparedStatementSetter(List<Student> students, String status){
return
new BatchPreparedStatementSetter(){
@Override
public int getBatchSize()
return students.size();
}
@Override
public void setValues(PreparedStatement ps int i){
Student student = students.get(i);
ps.setInt(1, student.getRollNo());
ps.setString(2, student.getName());
}
});
}
}
现在在您的原始代码中使用它:
// inject it
BatchPreparedStatementFactory batchPreparedStatementFactory;
public void updateData(List<Student> students, String status){
try{jdbcTemplate.batchUpdate("update query", batchPreparedStatementFactory.ofStudentsBatchPreparedStatementSetter(students, status );
}catch(Exception ex){}
}
现在你有两个组件和两个测试:
BatchPreparedStatementFactoryTest
(没有模拟)测试getBatchSize()
和setValues()
。 这是非常直接的。jdbcTemplate.batchUpdate()
是使用预期参数调用的,特别是BatchPreparedStatementFactory.ofStudentsBatchPreparedStatementSetter(...)
返回的实例。jdbcTemplate
、 BatchPreparedStatementFactory
和BatchPreparedStatementSetter
。例如第二种情况:
// mock the factory return
BatchPreparedStatementSetter batchPreparedStatementSetterDummyMock = Mockito.mock(BatchPreparedStatementSetter.class);
Mockito.when(batchPreparedStatementFactoryMock.ofStudentsBatchPreparedStatementSetter(students, status))
.thenReturn(batchPreparedStatementSetterDummyMock);
// call the method to test
updateData(students, status);
// verify that we call the factory with the expected params
Mockito.verify(jdbcTemplateMock)
.batchUpdate("update query", batchPreparedStatementSetterDummyMock);
就我个人而言,我不太喜欢那种过于精细的单元测试 mocking。 我会坚持使用@DataJpaTest
或更多的全局集成测试来断言与 JDBC/JPA 相关的事情。
正如@davidxxx 回答的那样,通过创建工厂来重构代码是一个很好的解决方案。 如果您不想创建工厂,您可以使用下面的解决方案对batchUpdate
调用中编写的逻辑进行单元测试。
import static org.mockito.Mockito.*;
@Test
public void testJDBCBatchUpdate() {
String expectedSQL = "Select * from TableName";
doAnswer(invocationOnMock -> {
String actualSQL =invocationOnMock.getArgumentAt(0, String.class);
assertEquals(expectedSQL, actualSQL);
PreparedStatement preparedStatementMock=Mockito.mock(PreparedStatement.class);
BatchPreparedStatementSetter setter =invocationOnMock.getArgumentAt(1, BatchPreparedStatementSetter.class);
setter.setValues(preparedStatementMock, 0);
verify(preparedStatementMock, times(1)).setObject(anyInt(), anyString());
int batchSize=setter.getBatchSize();
assertEquals(expectedBatchSize,batchSize);
return null;
}).when(jdbcTemplate).batchUpdate(anyString(), any(BatchPreparedStatementSetter.class));
List<Datum> data = service.getData();
verify(jdbcTemplate, times(1)).batchUpdate(anyString(),any(BatchPreparedStatementSetter.class));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.