Я пытаюсь протестировать некоторый код загрузки с использованием OkHttp3 и с треском провалился Цель: проверка загрузка файла изображения и проверка его работоспособности. Платформа: Android. Этот код работает в рабочей среде, но тестовый код не имеет никакого смысла.
Код продукта
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()
}
}
Тестовый код (JUnit5)
@ExtendWith(TempDirectory::class)
internal class FileDownloaderImplTest {
private val mockWebServer = MockWebServer()
private val logger = LoggingInterceptor(HttpLoggingInterceptor.Level.BODY) { msg -> println(msg) }
private val fileDownloader = FileDownloaderImpl(Schedulers.trampoline(), logger) {
mockWebServer.url("/$it")
}
@BeforeEach fun setup() {
mockWebServer.start()
}
@AfterEach fun teardown() {
mockWebServer.shutdown()
}
@Test fun downloadFile(@TempDir tempDirectory: Path) {
// Given
val res = javaClass.classLoader.getResource("green20.webp")
val f = File(res.path)
val buffer = Okio.buffer(Okio.source(f)).buffer()
mockWebServer.enqueue(MockResponse().setBody(buffer))
val destFile = tempDirectory.resolve("temp.webp").toFile()
// Verify initial condition
destFile.exists() shouldBe false
// When
fileDownloader.downloadFile("test.html", destFile)
// Then
.test()
.assertValue { file ->
file.exists() shouldBe true
file.length() shouldEqualTo 66 // FAIL: always 0
true
}
}
}
Подробнее
"green20.webp" - это файл, который существует в app/test/resources
. Когда я отлаживаю, все признаки того, что он существует. Что касается отладки, у меня есть точки останова в коде prod, и похоже, что у объекта Response (предположительно MockResponse
) нет тела. Я понятия не имею, почему это будет.
Актуальные идеи:
- Я не добавляю корректное тело ответа
- Файл как-то "открыт", поэтому его длина всегда равна 0, хотя на самом деле он не пустой.
EDIT
Я попытался удалить MockWebServer
из теста и инициировал real загрузку, и мой тест фактически прошел. Итак, я думаю, что я делаю что-то не так с MockResponse
и его корпусом. Любая помощь будет высоко ценится.