Skip to content
Advertisement

Write unit test for jdbcTemplate.batchUpdate() method

I have jdbcTemplate code, on which I am trying to write a unit test case.


     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){}
    
 }

But the problem is I am unable to cover the full code. I am able to cover till:

try{jdbcTemplate.batchUpdate(“update query”, new BatchPreparedStatementSetter(){

Test code snippet

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

}

Please help.

Advertisement

Answer

Here the difficulty is that the new BatchPreparedStatementSetter(){ ...} instance that contains the main logic that you want to test is a implementation detail of the updateData() method. It is defined only inside the tested method.
To solve that you have two classic approaches :

  • favor a test slice with @DataJpaTest (that is finally a partial integration test) that would be simpler since you will be able to test side effect and also more helpful as you assert the state in the DB and not the statements in your code.
  • Extract the BatchPreparedStatementSetter instance creation in a factory.
    In that way you could capture it inside your unit test.

For example :

@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());            
                 }
          });
     }
}

And use it now in your original code :

 // inject it
 BatchPreparedStatementFactory batchPreparedStatementFactory;

 public void updateData(List<Student> students, String status){
    try{jdbcTemplate.batchUpdate("update query", batchPreparedStatementFactory.ofStudentsBatchPreparedStatementSetter(students, status );
    }catch(Exception ex){}    
  }

Now you have two components and so two tests :

  • BatchPreparedStatementFactoryTest (without mocking) which tests getBatchSize() and setValues(). That is very straight.
  • your initial test (with mocking) that asserts that the jdbcTemplate.batchUpdate() is invoked with expected parameters, particularly the instance returned by BatchPreparedStatementFactory.ofStudentsBatchPreparedStatementSetter(...).
    To do that assertion, you should define several mocks : jdbcTemplate, BatchPreparedStatementFactory and BatchPreparedStatementSetter.

For example for the second case :

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

Personally I am not a big fan of that kind of unit tests with too fine mocking. I would stick to @DataJpaTest or more global integration tests to assert things related to JDBC/JPA.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement