使用Spock模拟JdbcTemplate时返回空列表的问题求助
解决Spock中模拟JdbcTemplate返回空列表的问题
我来帮你分析一下问题所在,其实不是Spock不能模拟JdbcTemplate,而是你的测试里有几个容易忽略的细节没处理好:
1. 遗漏了对QueryBuilderUtility的Mock交互
你的ProductService.findProducts方法首先会调用queryBuilderUtility.buildSelectQuery(productCodes)生成SQL语句,但在测试里你只Mock了JdbcTemplate,没有给queryBuilderUtility的buildSelectQuery方法设置返回值。这会导致productQuery变成null,而你MockJdbcTemplate.query时用了_ as String来匹配第一个参数——null并不是String类型,所以这个Mock交互根本没被触发,JdbcTemplate只能返回默认的空列表。
2. 测试块的结构不符合Spock规范
Spock的given-when-then块有明确的职责:
given:准备测试数据、设置Mock交互when:执行要测试的方法then:验证结果、断言
你在when块里加了assert products.size() == 3和println,这会打乱测试的执行顺序,也不符合Spock的最佳实践。
修复后的测试代码
class ProductServiceSpec extends Specification { JdbcTemplate jdbcTemplate = Mock() QueryBuilderUtility queryBuilderUtility = Mock() ProductService productService List<Long> productCodes = [33334L, 66754L, 56772L] TestUtil testUtil = new TestUtil() List<Product> products = testUtil.createProducts() def setup(){ productService = new ProductService(jdbcTemplate, queryBuilderUtility) } def 'Find Products for product codes'(){ given: // 先Mock queryBuilder,让它返回合法的SQL语句 1 * queryBuilderUtility.buildSelectQuery(productCodes) >> "SELECT * FROM products WHERE code IN (?, ?, ?)" // 再Mock JdbcTemplate的query方法,用宽松的参数匹配确保触发 1 * jdbcTemplate.query(_ as String, _ as ProductRowMapper, _ as Object[]) >> products when: List<Product> result = productService.findProducts(productCodes) then: // 验证结果是否符合预期 result.size() == 3 result == products } }
额外的优化建议
- 你的
ProductService同时用了@RequiredArgsConstructor和手动写的构造方法,其实@RequiredArgsConstructor会自动生成包含所有final字段的构造方法,手动写的构造方法可以删掉,避免冗余。 - 如果不想硬写SQL语句,也可以用
_来匹配buildSelectQuery的参数,比如1 * queryBuilderUtility.buildSelectQuery(_) >> "任意SQL",只要保证它返回非null的字符串即可。
这样修改后,你的Mock交互就能正确触发,返回你预设的products列表了。
内容的提问来源于stack exchange,提问作者BreenDeen
相关产品推荐
相关产品推荐

