Ktor 测试无法序列化正文。内容类型为:class ...但需要 OutgoingContent

问题描述 投票:0回答:2

所以尝试了解如何使用 testcontainers 测试 ktor 应用程序

这是我的代码

package com.app

import com.app.base.db.DbFactory
import com.app.features.auth.RegisterDTO
import com.app.plugins.*
import io.kotest.assertions.ktor.client.shouldHaveStatus
import io.kotest.core.extensions.install
import io.kotest.core.spec.style.FreeSpec
import io.kotest.extensions.testcontainers.JdbcTestContainerExtension
import io.ktor.client.*
import io.ktor.client.engine.apache.*
import io.ktor.client.request.*
import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import io.ktor.server.application.*
import io.ktor.server.plugins.contentnegotiation.*
import org.testcontainers.containers.PostgreSQLContainer
import io.ktor.server.testing.*
import kotlinx.serialization.json.Json
import org.jetbrains.exposed.sql.Database

class AuthSpec : FreeSpec({

    val postgres = PostgreSQLContainer<Nothing>("postgres").apply {
        withDatabaseName("test_appDB")
        startupAttempts = 1
        withUsername("test_viktor")
        withPassword("test_longPass")
        withExposedPorts(5432)
    }
    postgres.start()

    val ds = install(JdbcTestContainerExtension(postgres)) {
        poolName = "myconnectionpool"
        maximumPoolSize = 8
        idleTimeout = 10000
    }

    "register creator" - {
        testApplication {
            application {
                DbFactory.init(ds)
                configureSecurity()
                configureHTTP()
                configureMonitoring()
                configureSerialization()
                configureDependencyInjection()
                configureStatusPage()
                configureRouting()
            }

            val client = HttpClient(Apache) {}
            client.post("/api/v1/auth/register") {
                contentType(ContentType.Application.Json)
                setBody(RegisterDTO("[email protected]", "some", "some@sdfSDF"))
            }.apply {
                this.shouldHaveStatus(HttpStatusCode.OK)
            }
        }
    }

})

我确实希望这个测试能够正确运行,并且我可以在测试中看到绿色,但实际上我看到了错误

Fail to serialize body. Content has type: class com.app.features.auth.RegisterDTO, but OutgoingContent expected.
java.lang.IllegalStateException: Fail to serialize body. Content has type: class com.app.features.auth.RegisterDTO, but OutgoingContent expected.
If you expect serialized body, please check that you have installed the corresponding plugin(like `ContentNegotiation`) and set `Content-Type` header.
    at io.ktor.client.plugins.HttpSend$Plugin$install$1.invokeSuspend(HttpSend.kt:87)
    at io.ktor.client.plugins.HttpSend$Plugin$install$1.invoke(HttpSend.kt)
    at io.ktor.client.plugins.HttpSend$Plugin$install$1.invoke(HttpSend.kt)
    at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:123)
    at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
    at io.ktor.util.pipeline.SuspendFunctionGun.proceedWith(SuspendFunctionGun.kt:91)
    at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invokeSuspend(HttpCallValidator.kt:126)
    at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(HttpCallValidator.kt)
    at io.ktor.client.plugins.HttpCallValidator$Companion$install$1.invoke(HttpCallValidator.kt)
    at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:123)
    at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
    at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invokeSuspend(HttpRequestLifecycle.kt:35)
    at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(HttpRequestLifecycle.kt)
    at io.ktor.client.plugins.HttpRequestLifecycle$Plugin$install$1.invoke(HttpRequestLifecycle.kt)
    at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:123)
    at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:81)
    at io.ktor.util.pipeline.SuspendFunctionGun.execute$ktor_utils(SuspendFunctionGun.kt:101)
    at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
    at io.ktor.client.HttpClient.execute$ktor_client_core(HttpClient.kt:187)
    at io.ktor.client.statement.HttpStatement.executeUnsafe(HttpStatement.kt:107)
    at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:46)
    at io.ktor.client.statement.HttpStatement.execute(HttpStatement.kt:61)
    at com.app.AuthSpec$1$1$1.invokeSuspend(AuthSpec.kt:84)

我已经安装了很多用于测试的库,可能不需要它们,但这里是它们的依赖项

   //region tests
    testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version")
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
    testImplementation("io.ktor:ktor-server-test-host:$ktor_version")
    testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlin_version")

    testImplementation("io.kotest:kotest-runner-junit5:$kotest_version")
    testImplementation("io.kotest:kotest-assertions-core:$kotest_version")
    testImplementation("io.kotest:kotest-property:$kotest_version")
    testImplementation("io.kotest.extensions:kotest-extensions-testcontainers:1.3.2")
    testImplementation("org.testcontainers:testcontainers:$testcontainers_version")
    testImplementation("org.testcontainers:junit-jupiter:$testcontainers_version")
    testImplementation("org.testcontainers:postgresql:$testcontainers_version")
    testImplementation("io.kotest.extensions:kotest-assertions-ktor:1.0.3")
    //endregion
kotlin serialization ktor testcontainers kotest
2个回答
5
投票

您需要通过配置测试客户端来安装ContentNegotiation插件。


0
投票

将以下内容添加到

build.gradle.kts
(在本例中为
serialization.kotlinx.json
,但您可以使用
Gson
Jackson
):

implementation("io.ktor:ktor-client-content-negotiation:$ktor_version")
implementation("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")

并安装到客户端配置:

val client = HttpClient(Apache) {
    install(ContentNegotiation) {
        json()
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.