使用JpaRepository时能否在mock场景下校验其生成的SQL查询语句?
可行实现方案
你可以通过以下两种轻量方案实现无需真实数据库的SQL校验,两种方案都不需要依赖H2、容器化数据库:
方案1:使用Datasource Proxy(通用JPA实现)
Datasource Proxy是专门用于拦截JDBC调用的工具包,可以包装数据源捕获所有生成的SQL及参数,SQL生成逻辑完全由你的JPA实现、实体映射、数据库方言决定,不需要实际建立数据库连接。
实现步骤
- 引入依赖(Maven示例)
<dependency> <groupId>net.ttddyy</groupId> <artifactId>datasource-proxy</artifactId> <version>1.9</version> <scope>test</scope> </dependency>
- 测试环境配置代理数据源与SQL捕获逻辑
@TestConfiguration public class SqlCaptureConfig { // 存储捕获到的SQL列表 public static final List<String> CAPTURED_SQL = Collections.synchronizedList(new ArrayList<>()); @Bean @Primary public DataSource dataSource() { // 用空的嵌入式数据源做兜底,不需要实际初始化库 DataSource originalDataSource = new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .build(); // 包装为代理数据源 return ProxyDataSourceBuilder .create(originalDataSource) .listener(new QueryExecutionListener() { @Override public void beforeQuery(ExecutionInfo execInfo, List<QueryInfo> queryInfoList) { queryInfoList.forEach(q -> CAPTURED_SQL.add(q.getQuery())); } @Override public void afterQuery(ExecutionInfo execInfo, List<QueryInfo> queryInfoList) {} }) .build(); } }
- 编写测试用例,比对SQL
@SpringBootTest @AutoConfigureMockMvc @Import(SqlCaptureConfig.class) public class TControllerTest { @Autowired private MockMvc mockMvc; @BeforeEach void clearCapturedSql() { SqlCaptureConfig.CAPTURED_SQL.clear(); } @Test void testInsertSqlIsCorrect() throws Exception { // 执行你的原有接口测试逻辑 mockMvc.perform(put("path") .contentType(MediaType.APPLICATION_JSON) .characterEncoding("UTF8") .content(t) ).andExpect(status().isCreated()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)); // 校验生成的SQL assertEquals( "INSERT INTO t (column1, column2, column3) VALUES (?, ?, ?)", SqlCaptureConfig.CAPTURED_SQL.get(0) ); } }
如果需要校验参数值,Datasource Proxy也支持捕获PreparedStatement的入参,直接从QueryInfo的getParametersList获取即可
方案2:使用Hibernate StatementInspector(Hibernate作为JPA实现时可用)
如果你使用Hibernate作为JPA的实现,无需引入额外依赖,直接用Hibernate内置的StatementInspector接口即可拦截所有生成的SQL:
实现步骤
- 自定义StatementInspector实现
public class SqlCaptureInspector implements StatementInspector { public static final List<String> CAPTURED_SQL = Collections.synchronizedList(new ArrayList<>()); @Override public String inspect(String sql) { CAPTURED_SQL.add(sql); return sql; } }
- 测试配置中开启Inspector
在application-test.properties中添加配置:
spring.jpa.properties.hibernate.session_factory.statement_inspector=com.example.test.SqlCaptureInspector spring.jpa.hibernate.ddl-auto=none # 配置你实际使用的数据库方言,决定SQL生成规则 spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
- 测试用例和方案1一致,执行接口调用后直接比对
CAPTURED_SQL中的内容即可。
注意事项
两种方案都不需要实际建立数据库连接,SQL生成仅依赖你的实体映射配置、数据库方言,完全符合你的测试需求。
内容的提问来源于stack exchange,提问作者Stephan Hogenboom
相关产品推荐
相关产品推荐

