Grails 3.3.8单元测试中如何初始化控制器中的服务?
在Grails 3.3.8单元测试中使用自动生成的Service实现注入控制器
你现在手动实例化自定义实现类的方式虽然能跑,但确实存在和生产环境逻辑不一致的风险——毕竟Grails会基于你的FooService接口和GORM自动生成一套实现,这才是实际运行时控制器依赖的对象。要在单元测试里用上这套自动生成的实现,其实只需要调整测试的配置和依赖注入方式就行,下面给你两种可行的方案:
方案一:借助DomainUnitTest自动注入
这种方式是最简洁的,因为Grails的动态Service实现依赖GORM域类,实现DomainUnitTest接口后,测试框架会自动帮你初始化内存数据库、生成Service实现并完成注入:
import grails.testing.web.controllers.ControllerUnitTest import grails.testing.gorm.DomainUnitTest import spock.lang.Specification class FooControllerSpec extends Specification implements ControllerUnitTest<FooController>, DomainUnitTest<Foo> { void "test index"() { when: controller.index() then: response.json status == 200 } void "test show"() { given: // 提前在内存数据库中存入测试数据,和生产环境的Service逻辑完全对齐 def testFoo = new Foo(id: '000001400').save(flush: true, failOnError: true) when: params['id'] = '000001400' controller.show() then: status == 200 // 还可以验证返回的JSON数据和存入的实例一致 response.json.id == testFoo.id } }
关键说明:
- 实现
DomainUnitTest<Foo>后,测试框架会自动初始化GORM的内存数据库,同时生成FooService的动态实现,并注入到控制器的fooService属性中,完全不需要手动赋值。 - 你可以直接用GORM的
save方法准备测试数据,这样Service的get/list方法逻辑和生产环境完全一致,不会出现自定义实现的偏差。
方案二:手动获取动态生成的Service实例
如果不想引入DomainUnitTest,也可以通过测试上下文手动获取Grails生成的Service bean:
import grails.testing.web.controllers.ControllerUnitTest import grails.testing.services.ServiceUnitTest import grails.core.GrailsApplication import spock.lang.Specification class FooControllerSpec extends Specification implements ControllerUnitTest<FooController>, ServiceUnitTest<FooService> { GrailsApplication grailsApplication void setup() { // 从Grails应用上下文中获取自动生成的FooService实现 def dynamicFooService = grailsApplication.mainContext.getBean(FooService) controller.fooService = dynamicFooService } void "test index"() { when: controller.index() then: response.json status == 200 } void "test show"() { given: def testFoo = new Foo(id: '000001400').save(flush: true, failOnError: true) when: params['id'] = '000001400' controller.show() then: status == 200 } }
关键说明:
- 实现
ServiceUnitTest<FooService>接口后,测试框架会初始化Service的测试上下文,包含动态生成的实现类。 - 在
setup方法中,通过grailsApplication.mainContext获取到官方生成的Service bean,再注入到控制器中,同样能保证测试逻辑和生产环境一致。
注意事项
- 确保你的
Foo域类符合Grails GORM的配置要求(比如正确定义id字段等),否则动态生成的Service可能无法正常工作。 - 内存数据库的测试数据是方法隔离的,每个测试方法执行后会自动清空,不需要手动清理数据。
内容的提问来源于stack exchange,提问作者FrEqDe
相关产品推荐
相关产品推荐

