Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test SimpleJdbcCall

I need to create test for this code.

@Autowired
JdbcTemplate jdbcTemplate;

public List<Row> getData(int id) {
    // Preconditions here

    SimpleJdbcCall getCall = new SimpleJdbcCall(jdbcTemplate)
            .withSchemaName(SCHEMA)
            .withProcedureName(SP)
            .declareParameters( 
                // ...
            )
            .returningResultSet("result", (RowMapper<QuestionAnswerRow>) (rs, rowNum) -> .....);

    MapSqlParameterSource params = new MapSqlParameterSource();
    params.addValue("id", id);
    // other parameters here

    Map queryRes = getCall.execute(params);
    List<row> res = (List<row>) queryRes.get("result");
    return res;
}

Could you show me how can I mock here getCall.execute(params) response with Mockito?

like image 733
Vitalii Avatar asked Nov 19 '25 16:11

Vitalii


1 Answers

Your problem here is, that you create the whole getCall object inside your method, which makes it pretty much impossible to somehow inject a mock into that process.

There are a few possibilities here:

a) You can mock your jdbcTemplate and then try to get that to work by mocking all calls that getCall will make to the jdbcTemplate. Since the jdbcTemplate will probably do all the actual db work, this can work, but honestly, it's probably not worth the effort (since it's absolutely non-trivial).

b) You can switch the whole test to an integration-test, letting it run against an in-memory db, for example. Of course, there are many arguments against using an integration test as a substitute for an unit test, so probably this isn't the best way to go, either. It's possible, though, and using the Spring test utils and annotations it can be pretty simple.

c) This leaves us with a bit of work, which in this case means refactoring:

Since your problem is that you create the SimpleJdbcCall internally, one solution would be to to extract that part, for example, into a factory. This simplified example shows that:

@Component
class SimpleJdbcCallFactory {
   public SimpleJdbcCall create(JdbcTemplate template) {
       return new SimpleJdbcCall(template);
   }
}

Now you can add an @Autowired dependency to your class and then mock that depencency in your unit test...

@RunWith(MockitoJUnitRunner.class)
public class YourTestClassHere {

   @Mock
   private SimpleJdbcCallFactory simpleJdbcCallFactory;

   @InjectMocks
   private YourClassHere classToTest;

   @Test
   public void test() {
        SimpleJdbcCall mockedCall = Mockito.mock(SimpleJdbcCall.class);
        Mockito.when( simpleJdbcCallFactory.create(Mockito.any())).thenReturn(mockedCall);
        Mockito.when( mockedCall ).withSchemaName(Mockito.anyString()).thenReturn(mockedCall);
        // etc. unfortunately needed for fluent apis (unless they added those in mockito)
        Mockito.when( mockedCall.execute(Mockito.any()).thenReturn( ... );

        classToTest.getData(123);
   }

}
like image 159
Florian Schaetz Avatar answered Nov 22 '25 03:11

Florian Schaetz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!