Spock测试Kotlin suspend函数协程调用报错如何解决
报错原因
Kotlin中被suspend修饰的挂起函数,编译时会自动追加一个Continuation类型的隐式参数,仅允许在协程上下文或者其他挂起函数内部调用。
你遇到这个报错的核心原因:
- Spock框架基于Groovy实现,无法识别Kotlin的
suspend语法修饰符,直接在普通测试方法中调用挂起函数时,不会自动传入协程所需的隐式参数,也没有提供合法的协程执行上下文 - 控制器方法内部调用的
service.create(request)本身也是挂起函数,脱离协程上下文时本身就不允许直接调用
解决步骤
1. 引入官方协程测试依赖
首先在构建配置中添加Kotlin官方提供的协程测试库,以Gradle(Groovy DSL)为例:
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:${coroutines_version}"
请将${coroutines_version}替换为你项目中实际使用的协程版本,避免版本冲突。
2. 修改测试用例,在测试协程作用域中调用挂起函数
使用协程测试库提供的runTest方法构造测试专用的协程作用域,将挂起函数的调用逻辑包裹在作用域内部即可,修改后的测试代码如下:
import kotlinx.coroutines.test.runTest def 'It should create a ticket with success'() { given: def request = createRequest( TICKET_ID, TICKET_NAME, TICKET_PHONE, TICKET_CPF, TICKET_EMAIL, TICKET_COMMENT, TICKET_SUBJECT, TICKET_TAG ) when: def response = runTest { // 挂起函数必须在协程作用域内调用 controller.createTicket(request, authentication) } then: response != null }
注意事项
- 禁止使用
GlobalScope.launch等生产环境协程作用域编写测试,这类作用域不会阻塞测试线程等待协程执行完成,会导致测试逻辑提前结束,出现随机失败的问题 runTest会自动跳过协程中的delay等待,默认会等待所有启动的子协程执行完成,适合单元测试场景使用- 如果你的控制器方法本身不需要挂起逻辑,也可以移除方法上的
suspend修饰符,但如果下层service的create方法是挂起函数,控制器方法必须保留suspend修饰,否则内部调用service方法时也会报同样的错
内容的提问来源于stack exchange,提问作者Sérgio Oliveira
相关产品推荐
相关产品推荐

