You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用MockK模拟Gradle项目时存根方法未调用问题排查

解决Gradle任务单元测试中MockK存根不生效的问题

问题出在你用spyk(ProjectBuilder.builder().build())创建的Project对象上——Gradle的ExtensionContainer.getByType()方法是final方法,MockK默认不会拦截final方法,所以你写的every { project.extensions.getByType(...) }根本没生效,代码还是调用了真实Project的方法,自然找不到SourceSetContainer(因为ProjectBuilder创建的空项目本来就没有这个扩展)。

给你两种可行的修改方案:

方案一:让spyk支持拦截final方法

修改Project的spyk创建方式,加上relaxed = true,显式开启对final方法的拦截:

val project = spyk(ProjectBuilder.builder().build(), relaxed = true)

不过这种方式依赖真实Project的内部状态,可能带来不可控行为,更推荐用方案二。

方案二:完全Mock Project对象(更可控)

直接Mock Project接口,所有方法都能被存根,避免依赖真实Project的复杂逻辑:

@ExtendWith(MockKExtension::class)
class CopySourceTaskTest {
    @MockK
    lateinit var customExtension: MyCustomExtension

    @MockK
    lateinit var dependencyEnabled: Property<Boolean>

    @MockK
    lateinit var sourceSetContainer: SourceSetContainer

    @MockK
    lateinit var project: Project

    @MockK
    lateinit var extensionContainer: ExtensionContainer

    @MockK
    lateinit var mainSourceSet: SourceSet

    @BeforeEach
    fun setup() {
        every { customExtension.enableCopyConfig } returns dependencyEnabled
        // 关联Project与ExtensionContainer
        every { project.extensions } returns extensionContainer
        // 存根SourceSetContainer的获取
        every { extensionContainer.getByType(SourceSetContainer::class.java) } returns sourceSetContainer
        // 存根主源码集的获取
        every { sourceSetContainer.getByName(SourceSet.MAIN_SOURCE_SET_NAME) } returns mainSourceSet
        // 存根copy方法,避免执行真实文件操作
        every { project.copy(any()) } answers {}
        // 可选:存根buildDir路径
        every { project.buildDir } returns File("mock-build-dir")
    }

    @Test
    fun testCopy() {
        every { dependencyEnabled.get() } returns true
        
        // 直接创建任务实例并绑定mock的project
        val gradleTask = CopySourceTask(customExtension).apply {
            this.project = project
        }
       
        gradleTask.run()

        // 验证关键调用是否执行
        verify { project.copy(any()) }
        verify { sourceSetContainer.getByName(SourceSet.MAIN_SOURCE_SET_NAME) }
    }
}

额外提醒:如果坚持用真实Project对象测试,除了配置spyk,还需要手动向Project注册SourceSetContainer扩展,但这种方式测试依赖更重,不如Mock方案简洁可控。

内容的提问来源于stack exchange,提问作者newbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 02:17:03