Grails单元测试报错:executeQuery等字符串查询暂不被GORM支持
解决Grails单元测试中
executeQuery不支持的问题 我之前也踩过这个坑,在Grails单元测试里用@Mock模拟域类时,默认的内存数据存储确实不支持HQL字符串查询,下面给你几个可行的解决方案:
为什么会报错?
当你用@Mock(SomeDomain)做单元测试时,Grails用的是内存版的GORM实现(不是真正的Hibernate),这个轻量实现只支持基础CRUD和Criteria查询,没有实现HQL解析逻辑,所以调用executeQuery就会抛出那个不支持的异常。
方案1:把HQL改成Criteria查询(推荐)
这是最快速适配单元测试的方式,而且Criteria是Grails推荐的类型安全查询方式,可读性也更强。比如你原来的HQL:
def something = SomeDomain.executeQuery("SELECT sd FROM SomeDomain sd WHERE sd.thingId = :thingId", [thingId: args.thingId])
可以改成等价的Criteria:
def something = SomeDomain.createCriteria().list { eq('thingId', args.thingId) // 要是有其他条件,比如排序、分页,直接在这里加就行 // order('createTime', 'desc') // maxResults(10) }
这样改完后,单元测试就能正常跑了,而且测试速度也不会受影响。
方案2:换成集成测试
如果你实在不想改代码,必须保留HQL,那把测试改成集成测试就行。集成测试会启动完整的Spring上下文和Hibernate环境,支持所有GORM特性,包括HQL。
具体操作:
- 把测试文件从
src/test/groovy移到src/integration-test/groovy目录 - 去掉测试类上的
@TestFor和@Mock注解 - 添加
@Integration和@Rollback注解,让测试自动注入服务并回滚操作
示例集成测试代码:
import grails.testing.mixin.integration.Integration import grails.transaction.Rollback import spock.lang.Specification @Integration @Rollback class SomeServiceSpec extends Specification { SomeService someService // Grails会自动注入这个服务 void "nominal getSomeThing"() { setup: def args = ['thingId': 1L] when: def something = someService.getSomething(args) then: println "Thing: ${something}" } }
@Rollback会保证每个测试结束后数据库回到初始状态,不会影响其他测试。
方案3:在单元测试中启用Hibernate支持
Grails 3.x提供了HibernateTest特性,可以让单元测试使用Hibernate而不是内存存储,这样就能支持HQL了。不过这个方式会让测试启动速度变慢一点,适合必须在单元测试里用HQL的场景。
修改测试类如下:
import grails.testing.hibernate.HibernateTest import grails.testing.services.ServiceUnitTest import spock.lang.Specification class SomeServiceSpec extends Specification implements ServiceUnitTest<SomeService>, HibernateTest { // 指定要模拟的域类 @Override Class[] getDomainClassesToMock() { return [SomeDomain] } void "nominal getSomeThing"() { setup: def args = ['thingId': 1L] when: def something = service.getSomething(args) then: println "Thing: ${something}" } }
记得确保你的build.gradle里已经引入了grails-testing-support依赖(Grails 3.1.x默认应该是有的)。
总结一下
- 优先选方案1:改Criteria,速度快,符合Grails最佳实践
- 不想改代码就选方案2:集成测试,功能完整,最稳妥
- 非要在单元测试用HQL就选方案3:启用Hibernate测试支持
内容的提问来源于stack exchange,提问作者beechovsky
相关产品推荐
相关产品推荐

