接口自動(dòng)化測試中如何對(duì)xml 格式做斷言驗(yàn)證?
在服務(wù)端自動(dòng)化測試過程中,發(fā)起請(qǐng)求之后還需要對(duì)響應(yīng)值進(jìn)行驗(yàn)證,驗(yàn)證響應(yīng)信息符合預(yù)期值之后,這一條接口自動(dòng)化測試用例才算完整的通過。所以這一章節(jié),將會(huì)講解在接口自動(dòng)化測試中,是如何對(duì)服務(wù)端返回的 XML 格式響應(yīng)內(nèi)容做斷言驗(yàn)證。
環(huán)境準(zhǔn)備
Python 版本
安裝 requests_xml
pip install requests_xml
Java 版本
Rest-Assured 支持對(duì)xml 進(jìn)行斷言,參考接口測試框架章節(jié)安裝 Rest-Assured 即可。
Xml 解析方式
Python 有三種 XML 解析方式。
DOM 方式:它是文檔對(duì)象模型,是 W3C 組織推薦的標(biāo)準(zhǔn)編程接口,它將 XML 數(shù)據(jù)在內(nèi)存中解析成一個(gè)樹,通過對(duì)樹的操作來操作 XML。
SAX 方式:它是一個(gè)用于處理 XML 事件驅(qū)動(dòng)的模型,它逐行掃描文檔,一邊掃描一邊解析,對(duì)于大型文檔的解析擁有巨大優(yōu)勢,盡管不是 W3C 標(biāo)準(zhǔn),但它卻得到了廣泛認(rèn)可。
ElementTree 方式:相對(duì)于 DOM 來說擁有更好的性能,與 SAX 性能差不多,API 使用也很方便。
Python 版本
request 對(duì) XML 格式封裝的不強(qiáng),可以使用 request_xml 第三方庫,或者也可以自己封裝一個(gè) XML 的解析。
XML 響應(yīng)斷言
from requests_xml import XMLSession
# 設(shè)置session
session = XMLSession()
r = session.get("https://www.nasa.gov/rss/dyn/lg_image_of_the_day.rss")
# 打印所有的內(nèi)容
r.text
# links可以拿到響應(yīng)中所有的鏈接地址
r.xml.links
# raw_xml返回字節(jié)形式的響應(yīng)內(nèi)容
r.xml.raw_xml
# text返回標(biāo)簽中的內(nèi)容
r.xml.text
使用 xpath 斷言
requests_xml 庫也支持 XPath 表達(dá)式??梢酝ㄟ^ XPath 取出響應(yīng)中對(duì)應(yīng)字段的數(shù)據(jù),把取出來的數(shù)據(jù)放在 result 列表中,方便用例斷言。
XPath 用法:
def xpath(self, selector: str, *, first: bool = False, _encoding: str = None) -> _XPath:
? ? ?"""Given an XPath selector, returns a list of
? ? ?:class:`Element <Element>` objects or a single one.
? ? ?:param selector: XPath Selector to use.
? ? ?:param first: Whether or not to return just the first result.
? ? ?:param _encoding: The encoding format.
? ? ?"""
selector: 使用的 XPath 表達(dá)式
first: 是否只返回第一個(gè)查找的結(jié)果
xpath() 方法會(huì)返回一個(gè)查找到的對(duì)象的列表。
def test_xpath():
? ?session = XMLSession()
? ?r = session.get("https://www.nasa.gov/rss/dyn/lg_image_of_the_day.rss")
? ?# 通過xpath獲取所有l(wèi)ink標(biāo)簽的內(nèi)容
? ?item = r.xml.xpath("//link")
? ?result = []
? ?for i in item:
? ? ? ?# 把獲取的結(jié)果放進(jìn)列表中
? ? ? ?result.append(i.text)
? ?# 斷言
? ?assert 'http://www.nasa.gov/' in result
XML 解析
XML 是一種結(jié)構(gòu)化、層級(jí)化的數(shù)據(jù)格式,最適合體現(xiàn) XML 的數(shù)據(jù)結(jié)構(gòu)就是樹。可以使用 python 自帶的 xml.etree.ElementTree 來解析 XML 結(jié)構(gòu)。ElementTree 可以將整個(gè) XML 文檔轉(zhuǎn)化為樹,對(duì)整個(gè) XML 文檔的交互(讀取,寫入,查找元素),一般是在 ElementTree 層面進(jìn)行的。
然后再使用 findall 方法,去查找需要的 XPath 的數(shù)據(jù)。
import xml.etree.ElementTree as ET
# 自己封裝xml解析方法
session = XMLSession()
? ?r = session.get("https://www.nasa.gov/rss/dyn/lg_image_of_the_day.rss")
? ?# 獲取響應(yīng)內(nèi)容
? ?root = ET.fromstring(r.text)
? ?# 查找根元素
? ?em = root.findall(".")
? ?# print(item)
? ?items = root.findall(".//link")
? ?result = []
? ?# 遍歷
? ?for i in items:
? ? ? ?result.append(i.text)
? ?assert "http://www.nasa.gov/" in result
Java 版本
調(diào)用 body() 方法,第一個(gè)傳入 XPath 表達(dá)式,第二個(gè)傳入期望結(jié)果。
import static io.restassured.RestAssured.*;
import static org.hamcrest.core.IsEqual.equalTo;
public class Requests {
? ?public static void main(String[] args) {
? ? ? ? ? ? ? ?given().contentType("application/rss+xml; charset=utf-8").
? ? ? ? ? ? ? ?when().
? ? ? ? ? ? ? ?get("https://www.nasa.gov/rss/dyn/lg_image_of_the_day.rss")
? ? ? ? ? ? ? ?.then()
? ? ? ? ? ? ? ?.body("rss.channel.item[0].link",
? ? ? ? ? ? ? ?equalTo("http://www.nasa.gov/image-feature/mocha-swirls-in-jupiter-s-turbulent-atmosphere")).log().all();
? ?}
}
下面是這次請(qǐng)求的 XML 響應(yīng)內(nèi)容,rss.channel.item[0].link 這種類型的 XPath 表達(dá)式淺顯易懂,就是根據(jù) XPath 本身的層級(jí)一級(jí)一級(jí)進(jìn)行定位。rss 是其最外層的標(biāo)簽,然后依次是 channel 標(biāo)簽、item 標(biāo)簽、link 標(biāo)簽,其中同級(jí) item 有多個(gè)標(biāo)簽,所以需要通過下標(biāo) [0] 定位到第一個(gè) item 標(biāo)簽。通過這樣的定位方式,也可以獲取到想要的響應(yīng)內(nèi)容。
<rss version="2.0" xml:base="http://www.nasa.gov/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:media="http://search.yahoo.com/mrss/">
?<channel>
? ?<item>
? ? ?<title>Mocha Swirls in Jupiter’s Turbulent Atmosphere</title>
? ? ?<link>http://www.nasa.gov/image-feature/mocha-swirls-in-jupiter-s-turbulent-atmosphere</link>
? ? ?...省略
? ?</item>
? ?...省略
? ?<item>
? ? ?...省略...
? ?</item>
?</channel>
</rss>