WireMock存根中捕获Query Param并返回的Kotlin实现问题
问题分析
你的代码失效主要有两个核心原因:
urlPathMatching仅匹配URL的路径部分(即/v1/money),不包含查询参数;且你写的/v1/money?accounts=.*里的?是正则特殊字符,会导致路径匹配失败。- 直接在
okJson的静态字符串模板中调用Kotlin函数accountsList是无效的——WireMock无法识别这种自定义动态调用,必须用它支持的模板机制或动态响应生成方式。
可行实现方式
方式一:WireMock内置响应模板(推荐,简洁)
WireMock自带响应模板功能,可直接在响应中处理查询参数,无需额外写Kotlin工具函数。
首先确保启用模板扩展:
val portalWiremock = WireMockServer(options().extensions(ResponseTemplateTransformer(true))) portalWiremock.start()
然后编写存根:
portalWiremock.stubFor( get(urlPathEqualTo("/v1/money")) .withQueryParam("accounts", matching(".*")) // 可选:限制请求必须携带accounts参数 .willReturn( okJson( """ { "trackingId": "abcde12345", "accounts": [{{split request.query.accounts ',' | arrayMap '{{jsonEscape it}}' | join ','}}] } """.trimIndent() ).withTransformers("response-template") ) )
模板语法说明:
split request.query.accounts ',':将accounts参数按逗号分割为数组arrayMap '{{jsonEscape it}}':为每个元素添加引号并转义特殊字符join ',':拼接数组元素,配合外层[]生成合法JSON数组
方式二:Kotlin动态生成响应体
如果不想用WireMock模板,可直接通过函数动态构建响应内容:
portalWiremock.stubFor( get(urlPathEqualTo("/v1/money")) .willReturn( aResponse() .withStatus(200) .withHeader("Content-Type", "application/json") .withBody { request -> val accountsParam = request.queryParameter("accounts").firstValue() val accounts = accountsParam?.split(",") ?: emptyList() val accountsJson = accounts.joinToString(",", "[", "]") { "\"$it\"" } """ { "trackingId": "abcde12345", "accounts": $accountsJson } """.trimIndent() } ) )
这种方式完全用Kotlin代码处理参数,灵活度高,适合复杂的自定义逻辑。
方式三:自定义WireMock转换器(复用场景)
如果多个存根都需要处理类似的逗号分隔参数转JSON数组逻辑,可写一个自定义转换器:
class AccountsParamTransformer : ResponseTransformer() { override fun transform(request: Request, response: ResponseDefinition, files: FileSource, parameters: Parameters): ResponseDefinition { val accountsParam = request.queryParameter("accounts").firstValue() val accounts = accountsParam?.split(",") ?: emptyList() val accountsJson = accounts.joinToString(",", "[", "]") { "\"$it\"" } val modifiedBody = response.bodyAsString.replace("{{accountsList}}", accountsJson) return response.copy(body = modifiedBody) } override fun getName() = "accounts-param-transformer" }
启用并使用:
val portalWiremock = WireMockServer(options().extensions(AccountsParamTransformer())) portalWiremock.start() portalWiremock.stubFor( get(urlPathEqualTo("/v1/money")) .willReturn( okJson( """ { "trackingId": "abcde12345", "accounts": {{accountsList}} } """.trimIndent() ).withTransformers("accounts-param-transformer") ) )
关于捕获并返回查询参数的通用性
这种思路完全通用可行,是Mock场景中非常常见的需求(根据请求参数动态生成响应)。你之前的问题只是API使用方式错误,而非思路本身有问题,只要遵循WireMock的规则实现,就能稳定生效。
内容的提问来源于stack exchange,提问作者Maksym Rybalkin
相关产品推荐
相关产品推荐

