我在Rails(5.2.3(上有一个Ruby(2.6.5(应用程序,它已经成功地使用Sabon(2.12(通过SOAP/WSDL与FlightAware的FlightXML 2 API进行交互。但是,我在尝试为此功能编写 Minitest 测试时遇到了问题,使用 WebMock (3.7.6( 来存根 API 请求。
我的应用程序(通过 Savon(发出一个包含 XML 正文的请求,如以下示例所示:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:FlightXML2="http://flightxml.flightaware.com/soap/FlightXML2" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<FlightXML2:AirportInfoRequest>
<FlightXML2:airportCode>KDFW</FlightXML2:airportCode>
</FlightXML2:AirportInfoRequest>
</env:Body>
</env:Envelope>
我想使用 with 语句,以便存根仅响应元素中具有特定机场代码的请求。例如,如果我正在寻找"KDFW",那么包含<FlightXML2:airportCode>KDFW</FlightXML2:airportCode>
的请求应该匹配,但包含<FlightXML2:airportCode>CYYZ</FlightXML2:airportCode>
的请求不应该匹配。
现在,我通过在正则表达式中包含 XML 标记来使其工作:
icao_code = "KDFW"
response_body = "[the response I want]"
WebMock.stub_request(:post, "http://flightxml.flightaware.com/soap/FlightXML2/op").
with(body: /<FlightXML2:airportCode>#{icao_code}</FlightXML2:airportCode>/).
to_return(status: 200, body: response_body)
这感觉像是一个笨拙,特别是当 WebMock 的文档提到我可以使用hash_including
来匹配 XML 标记时。但是,无论我尝试什么,我都会收到典型的 WebMock 未注册请求错误,表明我与请求不匹配。以下是我到目前为止尝试过的with
语句:
with(body: hash_including({airport_code: icao_code})
with(body: hash_including({"airportCode": icao_code})
with(body: hash_including({"FlightXML2:airportCode": icao_code})
如何匹配特定的 XML 元素,而不必求助于将 XML 标记放在正则表达式中?
将请求与块匹配:
stub_request(:post, "http://flightxml.flightaware.com/soap/FlightXML2/op")
.with do |request|
# do something
end.to_return(status: 200, body: response_body)
块代码可能如下所示:
request_xml = Nokogiri::XML(request.body)
request_xml.xpath("//FlightXML2:airportCode").any? do |node|
node.content == icao_code
end
此方法还有一个额外的优点,因为您可以将调试器插入到上面的代码块中,并找出测试用例不起作用的原因。您可以在此处查看 Webmock 文档。