我在Spring Boot(v.2.2.1.RELEASE(应用程序的Java类中有以下代码:
@Inject
private JdbcTemplate jdbcTemplate;
@Inject
private MyRowCallbackHandler myRowCallbackHandler;
public void myMethod() {
jdbcTemplate.query(MY_QUERY, myRowCallbackHandler);
}
JDBC模板对象是org.springframework.JDBC.core.JdbcTemplate的实现,处理程序是org.springframework.jdb c.core.RowCallbackHandler.的实现
使用JUnit版本4和Mockito,我可以模拟查询方法从数据库中检索一行或多行,从而调用处理程序的processRow((方法吗?
感谢您的帮助。
我在自己的代码中遇到了这个问题,我想在这里分享解决方案,尽管它与上面模拟jdbcTemplate的情况略有不同。
@InjectMocks
private JdbcOperationRepository jdbcOperationRepository;
@Mock
private NamedParameterJdbcTemplate mockJdbcTemplate;
@Test
public void testMyResults() {
final ResultSet mockResult1 = mock(ResultSet.class);
when(mockResult1.getString(MY_COLUMN)).thenReturn(value);
// ... other when statements to mock the returned data
doAnswer(invocation -> {
RowCallbackHandler callbackHandler = invocation.getArgument(2);
callbackHandler.processRow(mockResult1);
callbackHandler.processRow(mockResult2);
return null;
}).when(mockJdbcTemplate).query(any(), any(), any(RowCallbackHandler.class));
}
我也遇到了同样的问题。首先,您必须记住,使用Junit测试,您几乎可以模拟春季启动中的任何东西。
我正在以通用模式编写解决方案,以便每个人都能了解它是如何实现和使用的。
假设我们在BookService.java类中实现了一个函数:
@Service
public class BookService {
@Inject
private NamedParameterJdbcOperations jdbcTemplate;
@Inject
private FileHelper fileHelper;
public List<BookDTO> getBooks(Long libraryId){
String sql = fileHelper.getFileContents("SQL_FILE_PATH");
Map<String, Object> parameterMap = new HashMap<>();
if(libraryId!=null){
parameterMap.put("libraryId", libraryId);
}
List<BookDTO> books = new ArrayList<>();
jdbcTemplate.query(sql, parameterMap, rs -> {
BookDTO book = new BookDTO();
book.setId(rs.getLong("id"));
book.setName(rs.getString("name"));
if(rs.getObject("librarian") != null){
book.setLibrarian(rs.getString("librarian"));
}
books.add(book);
});
return books;
}
}
现在,我们想模拟上述服务类的jdbcTemplate.query()
方法的功能。
我们的测试应该以这种模式编写:
public class BookServiceMockTest {
@Mock
private NamedParameterJdbcOperations jdbcTemplate;
@Mock
private FileHelper fileHelper;
private BookService mockBookService;
@Before
public void setup(){
mockBookService = new BookService();
// using reflectionUtils setFields of the fileHelper and jdbcTemplate.
// ....
}
@Test
public void getBooksTest(){
when(fileHelper.getFileContents("SQL_FILE_PATH")).thenReturn("SOME SQL");
doAnswer(invocation -> {
// we are going to mock ResultSet class.
ResultSet rs = Mockito.mock(ResultSet.class);
when(rs.getLong("id")).thenReturn(1L);
when(rs.getString("name")).thenReturn("Game of Thrones");
// this will mock the if() statement
when(rs.getObject("librarian")).thenReturn("John Doe");
// this will mock the actual get statement call on getString() inside the if statement
when(rs.getString("librarian")).thenReturn("John Doe");
// the argument index is important here.
// we are doing getArgument(2).
// This means the third parameter passed in the jdbcTemplate.query(Param0, Param1, Param2) in the BookService.getBooks() function.
RowCallbackHandler rch = (RowCallbackHandler) invocation.getArgument(2);
// as we are mocking only one row..
rch.processRow(rs);
/* // if we wanter two or more results:
when(rs.getLong("id")).thenReturn(1L).thenReturn(2L);
when(rs.getString("name")).thenReturn("Game of Thrones").thenReturn("Dance of the Dragon");
int n = 2; // no of rows..
for(int i=0; i<n; i++){
rch.processRow(rs);
}
*/
return null;
})
// the parameters used here are important. Any mismatch will result in unsuccessful.
.when(jdbcTemplate).query(eq("SOME SQL"), anyMap(), any(RowCallbackHandler.class));
List<BookDTO> books = mockBookService.getBooks(anyLong());
verify(jdbcTemplate, times(1)).query(eq("SOME SQL"), anyMap(), any(RowCallbackHandler.class));
assertThat(books).hasSize(1);
}
}
我希望这能满足你的需求!