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

如何Mock Kotlin标准库中File的outputStream()扩展函数?

如何Mock Kotlin标准库中的File.outputStream()扩展函数进行单元测试

问题场景

我有一个从流端点下载内容的方法,需要为其编写单元测试。核心问题是要Mock Kotlin标准库中File的扩展函数outputStream(),该函数定义在kotlin-stdlib的FileReadWrite中:

@kotlin.internal.InlineOnly
public inline fun File.outputStream(): FileOutputStream {
    return FileOutputStream(this)
}

下载方法实现如下:

override fun download(url: String, targetFile: File): Single<File> {
    return Single.fromCallable {
            fileDownloadApi
            .downloadFile(url)
            .execute()
            .body()?.byteStream()?.use { input ->
                targetFile.outputStream().use { output ->
                    FileUtil.copyFile(input, output)
                    return@fromCallable targetFile
                }
            }
        targetFile
    }
}

我已传入Mock的targetFile,但MockoutputStream()时出现错误,测试代码如下:

val mockFileOutputStream = mockk<FileOutputStream>()
val mockTargetFile = mockk<File>()
mockkStatic("kotlin.io.FilesKt")  // 该扩展函数的JVM类名为FilesKt
every { File("abc").outputStream() } returns mockFileOutputStream

service.download("", mockTargetFile)
    .subscribe(testObserver)

报错信息:

io.mockk.MockKException: Missing mocked calls inside every { ... } block: make sure the object inside the block is a mock

错误原因

你错误地针对新创建的File("abc")实例设置了outputStream()的Mock行为,但测试中传入的是独立的mockTargetFile对象,两者完全无关。而且File("abc")不是Mock对象,MockK无法识别这个调用的Mock配置,因此抛出错误。

另外,outputStream()是内联扩展函数,MockK需要针对已Mock的File实例来配置行为,而非任意File实例。

解决方案

修改测试代码,针对传入的mockTargetFile来设置outputStream()的返回值,同时按需MockFileUtil.copyFile避免执行实际文件操作:

val mockFileOutputStream = mockk<FileOutputStream>()
val mockTargetFile = mockk<File>()
// Mock扩展函数所在的类
mockkStatic("kotlin.io.FilesKt")

// 关键:在Mock的targetFile上配置outputStream()的行为
every { mockTargetFile.outputStream() } returns mockFileOutputStream

// 如果FileUtil.copyFile是静态方法或需要隔离,也需要Mock
mockkStatic(FileUtil::class)
every { FileUtil.copyFile(any(), any()) } just Runs

// 执行测试
service.download("", mockTargetFile)
    .subscribe(testObserver)

关键说明

  1. 针对Mock实例配置行为:测试中下载方法调用的是传入的mockTargetFile的outputStream(),因此必须在这个Mock对象上设置返回值,而非新创建的File实例。
  2. Mock依赖的工具方法:FileUtil.copyFile会执行实际的流拷贝逻辑,为了测试隔离,需要Mock这个方法避免副作用。
  3. 内联扩展函数的Mock:MockK对Kotlin内联扩展函数的支持需要通过mockkStatic指定扩展函数所在的JVM类(这里是kotlin.io.FilesKt),然后针对Mock实例配置行为即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 17:06:27