Search code examples
javaarraysjunitmockingmockito

How can I mock a call to JdbcTemplate.query(String, Object[], int[] RowMapper<T>) in my JUnit tests? (specifically the arrays)


I want to mock this method in JdbcTemplate:

    public <T> List<T> query(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper) throws DataAccessException {
        return result(query(sql, args, argTypes, new RowMapperResultSetExtractor<>(rowMapper)));
    }

I'm using JUnit 5 and Hamcrest.

I've tried numerous things, the one I feel should have worked is this:

when(db.query(anyString(), any(Object[].class), any(int[].class), new IdRowMapperImpl())).thenReturn(profileIds);

but it doesn't. What am I doing wrong here? How can I mock the arrays?


Solution

  • The mock that you thought should work won't work because you are using argument matchers and explicit values at the same time. If you want to use an explicit value along with matchers, you need to let mockito know that with the eq matcher.

    when(db.query(anyString(), any(Object[].class), any(int[].class), eq(new IdRowMapperImpl()))).thenReturn(profileIds);
    

    However, this also will not work because the new IdRowMapperImpl() will be a different object than the one passed to passed in the actual query.

    Finally, declaring specific types during a when mock can often be counterproductive. Unless you want to specifically return a different object depending on the values passed, then when(db.query(any(), any(), any(), any())).thenReturn(profileIds); can be just as useful. You can then use verify to assert that the expected method was called, and that the expected values were actually passed to it.

    Maybe something like this:

    @Test
    public void testRetrieveData()
    {
      String expectedQuery = "THIS IS MY QUERY";
      ArgumentCaptor<Object> objectCaptor = ArgumentCaptor.forClass(Object.class);
      ArgumentCaptor<RowMapper> mapperCaptor = ArgumentCaptor.forClass(RowMapper.class);
      when(db.query(any(), any(), any(), any())).thenReturn(profileIds);
     
      MyDao.getMyData();
    
      verify(db, times(1)).query(eq(expectedQuery), (Object[]) objectCaptor .capture(), any(int[].class), mapperCaptor.capture());
      assertEquals(expectedObjectArray, objectCaptor.getValue());
      assertTrue(mapperCaptor.getValue() instanceof IdRowMapperImpl);
    }