Уменьшение дублирования кода при тестировании KtorClient

Я создаю сервис поверх клиента Ktor. Моя полезная нагрузка - это XML, и поэтому упрощенная версия моего клиента выглядит так:

      class MavenClient(private val client : HttpClient) {

    private suspend fun getRemotePom(url : String) =
        try{ MavenClientSuccess(client.get<POMProject>(url)) }catch (e: Exception) { MavenClientFailure(e) 
    }

    companion object {
        fun getDefaultClient(): HttpClient {
            return HttpClient(Apache) {
                install(JsonFeature) {
                    serializer = JacksonSerializer(jackson = kotlinXmlMapper)
                    accept(ContentType.Text.Xml)
                    accept(ContentType.Application.Xml)
                    accept(ContentType.Text.Plain)
                }
            }
        }
    }
}

Обратите внимание на использование настраиваемого XMLMapper, прикрепленного к настраиваемому классу данных.

Я хочу протестировать этот класс и следовать документации.

Я получаю следующий код для своего тестового клиента:

      private val mockClient = HttpClient(MockEngine) {
    engine {
        addHandler { request ->
            when (request.url.fullUrl) {
                "https://lengrand.me/minimal/1.2/minimal-1.2.pom" -> {
                    respond(minimalResourceStreamPom.readBytes()
                    , headers = headersOf("Content-Type" to listOf(ContentType.Application.Xml.toString())))
                }
                "https://lengrand.me/unknown/1.2/unknown-1.2.pom" -> {
                    respond("", HttpStatusCode.NotFound)
                }
                else -> error("Unhandled ${request.url.fullUrl}")
            }
        }
    }
    // TODO : How do I avoid repeating this again ? That's my implementation?!
    install(JsonFeature) {
        serializer = JacksonSerializer(jackson = PomParser.kotlinXmlMapper)
        accept(ContentType.Text.Xml)
        accept(ContentType.Application.Xml)
        accept(ContentType.Text.Plain)
    }
}
private val Url.hostWithPortIfRequired: String get() = if (port == protocol.defaultPort) host else hostWithPort
private val Url.fullUrl: String get() = "${protocol.name}://$hostWithPortIfRequired$fullPath"

private val mavenClient = MavenClient(mockClient)

Теперь меня не беспокоит сам Mapper, потому что я тестирую его напрямую. Однако что меня беспокоит, так это то, что мне, по сути, приходится дублировать полную логику моего клиента, чтобы проверить поведение? Это кажется очень хрупким, потому что, например, это приведет к сбою моих тестов и их придется обновлять, если я перейду на Json завтра. То же самое, если я, например, начну использовать проверку ответа. Это еще более верно для другого клиента, где я использую defaultRequest, который я тоже должен полностью скопировать:

      private val mockClient = HttpClient(MockEngine) {
    install(JsonFeature) {
        serializer = JacksonSerializer(mapper)
        accept(ContentType.Application.Json)
    }
    defaultRequest {
        method = HttpMethod.Get
        host = "api.github.com"
        header("Accept", "application/vnd.github.v3+json")
        if (GithubLogin().hasToken()) header("Authorization", GithubLogin().authToken)
    }

Я что-то делаю неправильно? Я слишком много тестирую? Мне любопытно, как я могу это улучшить.

Большое спасибо за ваш вклад!

PS: Не имеет отношения, но на странице о тестировании на Ktor упоминается добавление зависимости к implementation. Похоже, я должен использовать testImplementation вместо этого, чтобы не отправлять библиотеку вместе с моим приложением?

1 ответ

В предназначен для заглушки реальной реализации HTTP-клиента для тестирования объектов, которые его используют. Проблема дублирования, с которой вы сталкиваетесь, заключается в том, что ответственность за преобразование тела ответа лежит на клиенте. Поэтому я предлагаю либо использовать непосредственно для преобразования тела ответа (в этом случае вам не нужно использовать ) или извлеките общую конфигурацию в функции расширения и вызовите ее для обоих движков.

Другие вопросы по тегам