我正在为我的java应用程序构建一个groovy rest客户端,以便与测试自动化一起使用。我最初用httpBuilder编写服务,但不知道如何解析响应。对于非200个响应,我得到了一个异常,我可以捕获它并在消息上断言。更新后,我可以解析响应,但只要我得到一个非200的响应,它就会尝试将其解析为我的对象,然后抛出一个无用的“missingProperty”异常。该文档展示了如何使用response.parser <CONTENT_TYPE>, { config, fs ->...}解析响应,以及如何使用response.success{fs -> ...}或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响应作为汽车对象加载。
额外的好处:为什么我必须使用显式的属性映射,而不是像文档中那样使用groovy类型转换?
json(config, fs).collect { x -> x as Car }更新-为了澄清,这不是我的实际来源。我遇到了一个在WAS上运行的专有内部API,但我不能完全控制它。我正在编写API的业务逻辑,但响应是使用WAS和专有库进行编组/解组的,我无权访问这些库。为了保护无辜的人/我的工作,名字都被改了。这些是我从初始post开始尝试的变通方法:这会在非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对象。我必须显式地设置新对象的道具。这不是什么大问题,但它让我怀疑我是否配置了其他错误的东西。
发布于 2017-11-02 21:08:59
您可以在failure处理程序中抛出一个异常,它将执行您正在寻找的操作:
response.failure { fs ->
throw new IllegalStateException('No car found')
}我不确定您测试的是哪台服务器,所以我使用Ersatz编写了一个测试
import com.stehno.ersatz.ErsatzServer
import spock.lang.AutoCleanup
import spock.lang.Specification
import static com.stehno.ersatz.ContentType.APPLICATION_JSON
class CarClientSpec extends Specification {
@AutoCleanup('stop')
private final ErsatzServer server = new ErsatzServer()
def 'successful get'() {
setup:
server.expectations {
get('/cars/make/Toyota').responder {
content '[{"make":"Toyota","model":"Corolla"}]', APPLICATION_JSON
}
}
CarClient client = new CarClient(server.httpUrl)
when:
List<Car> cars = client.getCars('Toyota')
then:
cars.size() == 1
cars.contains(new Car('Toyota', 'Corolla'))
}
def 'failed get'() {
setup:
server.expectations {
get('/cars/make/Ford').responds().code(404)
}
CarClient client = new CarClient(server.httpUrl)
when:
client.getCars('Ford')
then:
def ex = thrown(IllegalStateException)
ex.message == 'No car found'
}
}请注意,我必须让您的客户端拥有一个可配置的基本url (而Car需要@Canonical注释)。如果你还没有读过关于Take a REST with HttpBuilder-NG and Ersatz的博客文章,我建议你读一读,因为它提供了一个很好的概述。
我不确定你的奖金问题是什么意思。
https://stackoverflow.com/questions/47064107
复制相似问题