我正在为我的 java 应用程序构建一个 groovy rest 客户端,以用于测试自动化。我最初在 httpBuilder 中编写了服务,但不知道如何解析响应。在非 200 响应中,我得到了一个异常,我可以在消息中捕获并断言。未找到、错误请求等。更新后,我可以解析响应,但每当我收到非 200 响应时,它都会尝试将其解析为我的对象,然后抛出一个无用的“missingProperty”异常。该文档显示了如何使用 , 解析响应response.parser <CONTENT_TYPE>, { config, fs ->...}
,以及如何使用response.success{fs -> ...}
, or对状态代码进行分支response.when(<CODE>){fs -> ...}
,但不显示如何仅解析成功并使用不同的逻辑来解析失败。我目前的代码如下:
import groovyx.net.http.ChainedHttpConfig
import groovyx.net.http.FromServer
import groovyx.net.http.HttpBuilder
import groovyx.net.http.NativeHandlers
import static groovyx.net.http.ContentTypes.JSON
import static groovyx.net.http.NativeHandlers.Parsers.json
class CarClient {
private final HttpBuilder http
CarClient() {
http = HttpBuilder.configure {
request.uri = "localhost:8080"
request.encoder JSON, NativeHandlers.Encoders.&json
}
}
List<Car> getCars(make) {
http.get(List) {
request.uri.path = "/cars/make/${make}"
response.failure { fs ->
println("request failed: ${fs}")
}
response.parser JSON, { ChainedHttpConfig config, FromServer fs ->
json(config, fs).collect { x -> new Car(make: x."make", model: x."model") }
}
}
}
}
class Car {
def make
def model
}
然后我的 spock 测试:
def "200 response should return list of cars"() {
when:
def result = client.getCars("honda")
then:
result.size == 3
result[0].make == "honda"
result[0].model == "accord"
}
def "404 responses should throw exception with 'not found'"() {
when:
client.getCars("ford")
then:
final Exception ex = thrown()
ex.message == "Not Found"
}
在旧版本下,第一次测试失败,第二次测试通过。在新版本下,第一次测试通过,第二次测试失败。我也从来没有真正看到过这request failed:...
条消息。我刚得到一个groovy.lang.MissingPropertyException
。当我逐步完成时,我可以看到它试图将not found
响应加载为 Car 对象。
奖励:为什么我必须使用显式属性映射而不是像文档中那样的常规转换?
json(config, fs).collect { x -> x as Car }
更新 - 为澄清起见,这不是我的实际来源。我遇到了在 WAS 上运行的专有内部 API,我无法完全控制它。我正在编写 API 的业务逻辑,但正在使用我无权访问的 WAS 和专有库对响应进行编组/解组。名称已更改以保护无辜者/我的工作。这些是我自最初发布以来尝试过的解决方法:这会在非 200 响应上正确触发故障块,但解析失败并IO - stream closed
出现错误。此外,我在失败块中抛出的任何异常都会包装在 RuntimeException 中,这会阻止我访问信息。我已经尝试按照文档中的建议将它包装在一个传输异常中,但是当我得到它时它仍然是一个 RuntimeException。
List<Car> getCars(make) {
http.get(List) {
request.uri.path = "/cars/make/${make}"
response.failure { fs ->
println("request failed: ${fs}")
throw new AutomationException("$fs.statusCode : $fs.message")
}
response.success { FromServer fs ->
new JsonSlurper().parse(new InputStreamReader(fs.getInputStream, fs.getCharset())).collect { x -> new Car(make: x."make", model: x."model") }
}
}
}
}
这个在 200 个带有条目的响应上正确解析,200 个没有条目的响应仍然抛出缺少属性异常。与前面的 impl 一样,AutomationException 被包装,因此没有用处。
List<Car> getCars(make) {
http.get(List) {
request.uri.path = "/cars/make/${make}"
response.parser JSON, { ChainedHttpConfig config, FromServer fs ->
if (fs.statusCode == 200) {
json(config, fs).collect { x -> new Car(make: x."make", model: x."model") }
} else {
throw new AutomationException("$fs.statusCode : $fs.message")
}
}
}
}
关于奖金,我遵循的指南显示了将json(config, fs)
输出隐式转换为 Car 对象。我必须明确设置新对象的道具。没什么大不了的,但这让我想知道我是否错误地配置了其他东西。