为jdbcTemplate.batchUpdate()方法编写单元测试

时间:2020-07-25 06:14:43

标签: java unit-testing junit mockito jdbctemplate

我有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(“更新查询”,新 BatchPreparedStatementSetter(){

测试代码段

@Test
public void testMe(){
List<Student> students = new ArrayList<>();
 mockedObject.updateData(students ,"success");

}

请帮助。

1 个答案:

答案 0 :(得分:2)

困难之处在于,包含要测试的主要逻辑的new BatchPreparedStatementSetter(){ ...}实例是updateData()方法的实现细节。它仅在测试的方法内定义。
要解决您有两种经典方法:

  • 使用@DataJpaTest支持测试切片(这最终是部分集成测试),这会更加简单,因为您将能够测试副作用,并且在声明数据库中的状态而不是在数据库中声明状态时会更有用。您的代码中的语句。
  • 在工厂中提取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(...)返回的实例。
    为此,您应该定义几个模拟: jdbcTemplateBatchPreparedStatementFactoryBatchPreparedStatementSetter

例如第二种情况:

// 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);

就我个人而言,我不喜欢那种带有过于精细的模拟的单元测试。我会坚持使用@DataJpaTest或更多的全局集成测试来断言与JDBC / JPA有关的事情。