Android 使用MockWebServer测试OkHttp,使用缓冲区主体测试MockResponse
我试图测试一些涉及OkHttp3的下载代码,但失败得很惨。目标:测试下载图像文件并验证其是否有效。平台:安卓。这段代码正在生产中运行,但测试代码毫无意义 产品代码Android 使用MockWebServer测试OkHttp,使用缓冲区主体测试MockResponse,android,unit-testing,rx-java2,okhttp,okio,Android,Unit Testing,Rx Java2,Okhttp,Okio,我试图测试一些涉及OkHttp3的下载代码,但失败得很惨。目标:测试下载图像文件并验证其是否有效。平台:安卓。这段代码正在生产中运行,但测试代码毫无意义 产品代码 class FileDownloaderImpl internal constructor( private val ioScheduler: Scheduler, private val logger: LoggingInterceptor, private val parser: ((String) -&g
class FileDownloaderImpl internal constructor(
private val ioScheduler: Scheduler,
private val logger: LoggingInterceptor,
private val parser: ((String) -> HttpUrl)? // for testing only
) : FileDownloader {
@Inject constructor(logger: LoggingInterceptor) : this(Schedulers.io(), logger, null)
override fun downloadFile(url: String, destination: File): Single<File> {
Logger.d(TAG, "downloadFile\nurl = $url\nfile = $destination")
val client = OkHttpClient.Builder()
.addInterceptor(logger)
.build()
val call = client.newCall(newRequest(url))
return Single.fromCallable { call.execute() }
.doOnDispose { call.cancel() }
.subscribeOn(ioScheduler)
.map { response ->
Logger.d(TAG, "Successfully downloaded board: $response")
return@map response.body()!!.use { body ->
Okio.buffer(Okio.sink(destination)).use { sink ->
sink.writeAll(body.source())
}
destination
}
}
}
/**
* Creates the request, optionally parsing the URL into an [HttpUrl]. The primary (maybe only)
* use-case for that is for wrapping the URL in a `MockWebServer`.
*/
private fun newRequest(url: String): Request {
val httpUrl = parser?.invoke(url)
val builder = Request.Builder()
httpUrl?.let { builder.url(it) } ?: builder.url(url)
return builder.build()
}
}
更多细节
“green20.webp”是一个存在于app/test/resources
中的文件。当我调试时,所有的迹象都表明它存在。关于调试问题,我在prod代码中有断点,看起来响应对象(可能是MockResponse
)没有主体。我不知道为什么会这样
当前想法:
我尝试从测试中删除
MockWebServer
,并启动了真正的下载,我的测试实际上通过了。所以,我认为我在MockResponse
及其主体上做错了什么。任何帮助都将不胜感激。由于我不清楚的原因,Okio.buffer(Okio.source(file)).buffer()
总是返回一个空的缓冲区。但是,以下方法可行:
mockWebServer.enqueue(MockResponse().setBody(Buffer().apply {
writeAll(Okio.source(file))
}))
我现在要做的是手动创建一个新的缓冲区,并将整个文件写入其中。现在我的MockResponse
有了一个真实的身体
我仍然希望有人能解释一下原因……在BufferedSource
上的buffer()
方法没有将整个流读入该缓冲区以返回它。相反,它只允许您访问它从文件中预加载的字节,这些字节将在下次读取时返回
这是将文件加载到缓冲区的代码:
val buffer = Buffer()
file.source().use {
buffer.writeAll(it)
}
看起来您的代码和我的最终代码之间的显著区别在于,在将源代码写入缓冲区后,您正在关闭源代码(通过使用
)。我想我天真地希望Okio.source(文件)和writell能够处理这个问题。请确认我现在的理解是正确的?
val buffer = Buffer()
file.source().use {
buffer.writeAll(it)
}