我有一个运行 micronaut kotlin 应用程序的遗留服务,从基本角度来看,它是功能性的,并且 api 可以按预期运行,无需修改。问题是,当我针对 API 运行 Spek 测试时,请求失败并显示
错误的请求 io.micronaut.http.client.exceptions.HttpClientResponseException:错误请求 在 io.micronaut.http.client.netty.DefaultHttpClient$FullHttpResponseHandler.makeErrorFromRequestBody(DefaultHttpClient.java:2232)
当我通过以下方式点击“测试”API 时的应用程序
http://localhost:{port}/api/v1/test || http://localhost:{port}/api/v1/test?size=1&number=50&sort=ASC
api 正确处理请求。仅当我通过 gradle 测试任务实际运行测试时才会出现该问题。如果我在资源代码中添加调试,它永远不会到达
return HttpResponse.ok(mutableListOf("hello", "world"))
如果我修改api以具有String类型的查询参数
fun listTestValues(@Parameter(required = false, `in` = ParameterIn.QUERY) pagingQuery: String)
调试器确实停在正确的断点处。
最基本形式的代码结构是
interface TestApi {
fun listTestValues(@Parameter(required = false, `in` = ParameterIn.QUERY) pagingQuery: PagingQueryWS): HttpResponse<List<*>>
}
@Secured(SecurityRule.IS_AUTHENTICATED)
@Controller(
"/api/v1/test",
consumes = [MediaType.APPLICATION_JSON],
produces = [MediaType.APPLICATION_JSON]
)
class TestResource: TestApi {
@Get("{?pagingQuery*}")
override fun listTestValues(pagingQuery: PagingQueryWS): HttpResponse<List<*>> {
return HttpResponse.ok(mutableListOf("hello", "world"))
}
}
class TestResourceUT: Spek({
Feature("Test Resource UT") {
val applicationContext =
ApplicationContext.builder().build().start()
val embeddedServer = applicationContext.getBean(EmbeddedServer::class.java).start()
val client = HttpClient.create(embeddedServer.url)
Scenario("GET test api") {
lateinit var returned: List<*>
When("Responds successfully") {
val request = HttpRequest.GET<List<String>>("/api/v1/test")
returned = client
.toBlocking()
.retrieve(request, List::class.java)
}
Then("A List is returned with the found values") {
assertThat(returned.size).isEqualTo(2)
}
}
afterGroup {
client.close()
embeddedServer.close()
}
}
})
@Introspected
data class PagingQueryWS(
override val number: Int = PagingQuery.DEFAULT_PAGE_NUMBER,
override val size: Int = PagingQuery.DEFAULT_PAGE_SIZE,
override val sort: String? = null
): PagingQuery
interface PagingQuery {
val number: Int
val size: Int
val sort: String?
private fun getSort(): Sort {
return sort
?.split(",")
?.map {
val direction = it[0]
val field = it.substring(1)
if (direction == '-') {
Order.desc(field)
} else {
Order.asc(field)
}
}
?.let {
Sort.of(it)
}
?: Sort.UNSORTED
}
// External pages are 1-indexed but internal are 0-indexed
fun toPageable(): Pageable = Pageable.from(number - 1, size, getSort())
companion object {
const val DEFAULT_PAGE_SIZE = 50
const val DEFAULT_PAGE_NUMBER = 1
}
}
Kotlin 版本:1.9.25 麦克诺版本:3.9.7 斯佩克版本:2.0.7
经过几天的研究,我发现了该问题的解决方案/原因。这取决于单元测试的构建方式。在 TestResourceUT 中有
afterGroup {
client.close()
embeddedServer.close()
}
这是问题的根本原因。我的测试套件有多个测试,这些测试是通过 afterGroup 调用构建的,一旦删除这些测试,测试就全部通过,没有问题。
我无法说出这导致问题的具体原因,但我必须假设测试是同时运行的,并且当嵌入式服务器和 httpClient 为每个测试实例启动时,它们可能共享由client.close() 调用。