Grails 5运行测试时出现GrailsApplication未找到异常求助
解决Grails 5 + Java 11静态类测试中GrailsApplication找不到的问题
问题现象
在Grails 5、Java 11环境下开发插件时,静态类通过grails.util.Holders获取配置项,运行测试时触发以下错误:
java.lang.IllegalArgumentException: GrailsApplication not found at org.springframework.util.Assert.notNull(Assert.java:201) at grails.util.Holders.getGrailsApplication(Holders.java:129) at grails.util.Holders$getGrailsApplication.call(Unknown Source) at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125) at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130)
示例场景
配置文件(YAML)
--- configuration.value: "ABC"
静态类代码
import grails.util.Holders class SimpleClass { static String simpleMethod() { return Holders.getGrailsApplication().getConfig().getProperty("configuration.value") } }
测试代码
import spock.lang.Specification class SomeTest extends Specification { void "example"() { expect: SimpleClass.simpleMethod() == "ABC" } }
报错原因
测试执行阶段,Spring容器尚未完成初始化,Holders静态类中并未持有GrailsApplication实例,调用Holders.getGrailsApplication()时触发非空断言失败。
解决方案
方案一:改用依赖注入(推荐)
放弃使用Holders静态持有,将SimpleClass声明为Spring Bean,通过构造函数注入GrailsApplication:
import grails.core.GrailsApplication import org.springframework.stereotype.Component @Component class SimpleClass { private final GrailsApplication grailsApplication SimpleClass(GrailsApplication grailsApplication) { this.grailsApplication = grailsApplication } String simpleMethod() { return grailsApplication.config.getProperty("configuration.value") } }
对应测试代码修改为:
import spock.lang.Specification import grails.testing.spring.AutowiredTest class SomeTest extends Specification implements AutowiredTest { SimpleClass simpleClass void "example"() { expect: simpleClass.simpleMethod() == "ABC" } }
方案二:测试中手动初始化Holders(兼容旧代码)
如果必须保留静态方法,可以在测试生命周期中手动设置GrailsApplication到Holders:
import spock.lang.Specification import grails.testing.runtime.Runtime import grails.testing.runtime.RuntimeTest import grails.util.Holders class SomeTest extends Specification implements RuntimeTest { Runtime runtime def setup() { Holders.setGrailsApplication(runtime.grailsApplication) } void "example"() { expect: SimpleClass.simpleMethod() == "ABC" } def cleanup() { Holders.clear() } }
方案三:直接注入配置属性(更简洁)
若仅需获取单个配置值,可直接使用@Value注解注入,无需依赖GrailsApplication:
import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component @Component class SimpleClass { @Value('${configuration.value}') String configValue String simpleMethod() { return configValue } }
测试代码同方案一,通过AutowiredTest注入SimpleClass即可。
内容的提问来源于stack exchange,提问作者Joao G. Hartmann
相关产品推荐
相关产品推荐

