Ktor结合Testcontainers测试时出现请求体序列化失败报错
报错根因
异常的核心触发原因是你手动实例化的Apache引擎HttpClient没有安装客户端侧的ContentNegotiation序列化插件:
- 你仅在Ktor服务端的
application配置块中调用了configureSerialization(),这个配置仅作用于服务端,不会自动同步给你手动创建的HTTP客户端 - 未安装序列化插件的客户端无法自动将
RegisterDTO这类自定义对象转换为HTTP请求要求的OutgoingContent格式,即使你手动设置了Content-Type: application/json请求头,也会抛出序列化失败异常 - 额外问题:在
testApplication测试块中手动创建外部HttpClient是不必要的,这类客户端不会走测试宿主的内部调用通道,执行效率更低,也容易漏配必要插件。
修复方案
方案1:使用测试宿主内置客户端(推荐)
testApplication块内置了预配置的测试客户端,无需手动引入Apache引擎,直接在创建客户端时加装序列化插件即可,修改后的测试代码段如下:
"register creator" - { testApplication { application { DbFactory.init(ds) configureSecurity() configureHTTP() configureMonitoring() configureSerialization() configureDependencyInjection() configureStatusPage() configureRouting() } // 替换原来手动new HttpClient的逻辑 val client = createClient { install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { json(Json { isLenient = true ignoreUnknownKeys = true encodeDefaults = true }) } } client.post("/api/v1/auth/register") { contentType(ContentType.Application.Json) setBody(RegisterDTO("some@gmail.com", "some", "some@sdfSDF")) }.apply { this.shouldHaveStatus(HttpStatusCode.OK) } } }
该方案的客户端走测试宿主内部调用通道,不需要占用真实网络端口,测试执行速度更快。
方案2:自定义HttpClient补装插件
如果确实需要使用Apache引擎的自定义客户端,必须在客户端配置块中手动安装ContentNegotiation插件,修改代码如下:
val client = HttpClient(Apache) { install(io.ktor.client.plugins.contentnegotiation.ContentNegotiation) { json(Json { isLenient = true ignoreUnknownKeys = true encodeDefaults = true }) } }
额外注意事项
- 确保
RegisterDTO类添加了@kotlinx.serialization.Serializable注解,否则即使安装了序列化插件也无法正常完成对象序列化 - 测试依赖可做如下精简,移除冗余项:
- 删除
ktor-server-tests-jvm,高版本Ktor仅保留ktor-server-test-host即可 - 删除
kotlin-test-junit,和已引入的kotlin-test功能重复 - 删除
org.testcontainers:junit-jupiter,你已经使用Kotest对应的Testcontainers扩展,不需要JUnit5专属的Testcontainers依赖
- 删除
内容的提问来源于stack exchange,提问作者Victor Orlyk
相关产品推荐
相关产品推荐

