如何在Spock中Mock jOOQ查询结果?
问题描述
我正在开发Spring Boot应用,拥有如下Groovy类:
@Component class MyClass { DSLContext jooq MyClass(DSLContext jooq) { this.jooq = jooq } void execute(String value) { Table tbl // assume assigned a Table Field<?> fld // assume assigned a Field List<Record> records = jooq.select(DSL.asterisk()).from(tbl).where(fld.eq(value)).fetch() InsertValueStepN<Record> insertStep = jooq.insertInto(tbl)?.columns() // steps to complete insertStep elided insertStep?.execute() } }
同时拥有如下Spock单元测试类:
class MyClassTest extends Specification { DSLContext jooq = Mock() MyClass tested = new MyClass(jooq) def "execute doesn't throw exceptions when no records found"() { given: jooq.select(_ as Field[]) >> [] expect: tested.execute(null) } }
我的问题在于Mock jOOQ及jooq.select()的返回结果。需要让Spock通过jooq.select()的调用,但目前在调用from()时会出现空指针异常。也曾尝试使用jooq.select(DSL.asterisk()) >> [],但会抛出GroovyCastException,因为ArrayList类型的[]不是SelectSelectStep类型;而SelectSelectStep是接口,唯一实现类SelectImpl实例化难度大,且似乎并非正确方案。目前使用安全导航运算符(?.)让当前Mock通过测试,但这并非正确做法,希望能正确Mock jOOQ调用的结果,请问遗漏了什么?
解决方案
jOOQ的查询是链式调用,每个方法都返回不同的接口实例,不能直接返回List,必须逐层Mock每个步骤的返回值:
逐层Mock链式调用的每个环节
jOOQ的select()返回SelectSelectStep,from()返回SelectFromStep,where()返回SelectConditionStep,最终fetch()才返回List<Record>。所以需要为每个步骤Mock对应的接口实例。调整测试用例
修改后的Spock测试代码如下:def "execute doesn't throw exceptions when no records found"() { given: // Mock 查询链的每个步骤 SelectSelectStep selectStep = Mock() SelectFromStep fromStep = Mock() SelectConditionStep conditionStep = Mock() // 1. select() 返回对应的Mock对象 jooq.select(_ as Field[]) >> selectStep // 2. from() 返回对应的Mock对象 selectStep.from(_ as Table) >> fromStep // 3. where() 返回对应的Mock对象 fromStep.where(_ as Condition) >> conditionStep // 4. fetch() 返回预期的空列表 conditionStep.fetch() >> [] // 同时处理insert的链式调用(避免空指针) InsertIntoStep insertIntoStep = Mock() InsertColumnsStep columnsStep = Mock() jooq.insertInto(_ as Table) >> insertIntoStep insertIntoStep.columns(_ as Field[]) >> columnsStep // 如果后续还有values()等操作,继续Mock对应的返回,最后execute()可以返回任意预期值 columnsStep.values(_) >> Mock(InsertValueStepN) expect: tested.execute(null) }核心要点
- 不需要实例化jOOQ的内部实现类(如SelectImpl),Spock可以直接Mock接口类型,这是最简洁的方式。
- 链式调用的每一步都需要Mock返回对象,否则会出现空指针异常。
- 如果测试不关注insert逻辑的具体执行结果,只需Mock到能让代码正常走完的步骤即可,无需完全模拟真实执行流程。
内容的提问来源于stack exchange,提问作者randy
相关产品推荐
相关产品推荐

