ApiTestEngine,再也不侷限於 API 的測試

背景

從編寫《接口自動化測試的最佳工程實踐(ApiTestEngine)》至今,已經快半年了。在這一段時間內,ApiTestEngine通過持續迭代,也已徹底實現了當初預設的目標。html

然而,在設計ApiTestEngine之初只考慮了面向最常規的API接口類型,即HTTP響應內容爲JSON數據結構的類型。那麼,若是HTTP接口響應內容不是JSON,而是XMLSOAP,甚至爲HTML呢?web

答案是,不支持!正則表達式

不支持的緣由是什麼呢?json

其實,不論是何種業務類型或者技術架構的系統接口,咱們在對其進行測試時均可以拆分爲三步:api

  • 發起接口請求(Request)
  • 解析接口響應(Parse Response)
  • 校驗測試結果(Validation)

ApiTestEngine不支持XML/HTML類型的接口,問題偏偏是出如今解析接口響應校驗測試結果這兩個環節。考慮到校驗測試結果環節是依賴於解析接口響應,即須要先從接口響應結果中解析出具體的字段,才能實現與預期結果的校驗檢測,所以,制約ApiTestEngine沒法支持XML/HTML類型接口的根本緣由在於沒法支持對XML/HTML的解析。bash

也由於這個緣由,ApiTestEngine存在侷限性,無法推廣到公司內部的全部項目組。遇到JSON類型之外的接口時,只能再使用別的測試工具,體驗上非常不爽。數據結構

在經歷了一段時間的不爽後,我開始從新思考ApiTestEngine的設計,但願使其具備更大的適用範圍。經過前面的分析咱們也不難看出,解決問題的關鍵在於實現針對XML/HTML的解析器。架構

JSON接口的解析

在實現XML/HTML的解析器以前,咱們不妨先看下ApiTestEngineJSON解析器是怎麼工做的。app

JSON類型的數據結構中,不管結構有多麼複雜,數據字段都只可能爲以下三種數據類型之一:函數

  • 值(value)類型,包括數字、字符串等;該種數據類型的特色是不會再有下一層極的數據;
  • 字典(dict)類型;該種數據類型的特色是包含無序的下一層極的數據;
  • 列表(list)類型:該種數據類型的特色是包含有序的下一層極的數據。

基於這一背景,ApiTestEngine在實現JSON的字段提取器(extractor)時,就採用了點(.)的運算符。

例如,假如HTTP接口響應的headersbody爲以下內容:

response headers:

{
    "Content-Type": "application/json",
    "Content-Length": 69
}複製代碼

response body:

{
    "success": false,
    "person": {
        "name": {
            "first_name": "Leo",
            "last_name": "Lee",
        },
        "age": 29,
        "cities": ["Guangzhou", "Shenzhen"]
    }
}複製代碼

那麼對應的字段提取方式就爲:

"headers.content-type" => "application/json"
"headers.content-length" => 69
"body.success"/"content.success"/"text.success" => false

"content.person.name.first_name" => "Leo"
"content.person.age" => 29
"content.person.cities" => ["Guangzhou", "Shenzhen"]
"content.person.cities.0" => "Guangzhou"
"content.person.cities.1" => "Shenzhen"複製代碼

能夠看出,經過點(.)運算符,咱們能夠從上往下逐級定位到具體的字段:

  • 當下一級爲字典時,經過.key來指定下一級的節點,例如.person,指定了content下的person節點;
  • 當下一級爲列表時,經過.index來指定下一級的節點,例如.0,指定了cities下的第一個元素。

定位到具體字段後,咱們也就能夠方便地提取字段值供後續使用了,做爲參數或者進行結果校驗都可。

實現XML/HTML的解析器

從點(.)運算符的描述形式上來看,它和XML/HTMLxpath十分相似。既然如此,那咱們針對XML/HTML類型的接口,是否能夠基於xpath來實現解析器呢?

在大多數狀況下的確能夠。例如,針對以下HTML頁面,當咱們要獲取標題信息時,咱們就能夠經過xpath來指定提取字段:body/h1

<html>
    <body>
        <h1>訂單頁面</h1>
        <div>
            <p>訂單號:SA89193</p>
        </div>
    </body>
</html>複製代碼

然而,若是咱們想獲取訂單號(SA89193)時,使用xpath就沒有辦法了(經過body/div/p獲取到的是訂單號:SA89193,還需進一步地進行處理)。

那除了xpath,咱們還能使用什麼其它方法從XML/HTML中提取特定字段呢?

因爲早些年對LoadRunner比較熟悉,所以我首先想到了LoadRunnerweb_reg_save_param函數;在該函數中,咱們能夠經過指定左右邊界(LB & RB)來查找字段,將其提取出來並保存到變量中供後續使用。借鑑這種方式雖然可行,但在描述方式上仍是比較複雜,特別是在YAML測試用例的extract中描述的時候。

再一想,這種方式的底層實現不就是正則表達式麼。並且咱們經過Python腳本解析網頁時,採用正則表達式來對目標字段進行匹配和提取,的確也是通用性很是強的方式。

例如,假設咱們如今想從http://debugtalk.com首頁中提取出座右銘,經過查看網頁源代碼,咱們能夠看到座右銘對應的位置。

<h2 class="blog-motto">探索一個軟件工程師的無限可能</h2>複製代碼

那麼,要提取「探索一個軟件工程師的無限可能」字符串時,咱們就可使用正則表達式r"blog-motto\">(.*)</h2>"進行匹配,而後使用regexgroup將匹配內容提取出來。

對應的Python腳本實現以下所示。

>>> import re, requests
>>> resp = requests.get("http://debugtalk.com")
>>> content = resp.text
>>> matched = re.search(r"blog-motto\">(.*)</h2>", content)
>>> matched.group(1)
'探索一個軟件工程師的無限可能'複製代碼

思路肯定後,實現起來就很快了。

此處省略256字。。。

最終,我在ApiTestEngine中新增實現了一個基於正則表達式的提取器。使用形式與JSON解析保持一致,只須要將以前的點(.)運算符更改成正則表達式便可。

仍是前面提取座右銘的例子,咱們就能夠經過YAML格式來編寫測試用例。

- test:
 name: demo
 request:
 url: http://debugtalk.com/
 method: GET
 extract:
 - motto: 'blog-motto\">(.*)</h2>'
 validate:
 - {"check": "status_code", "expected": 200}複製代碼

須要說明的是,指定的正則表達式必須知足r".*\(.*\).*"的格式要求,必須而且只能有一個分組(即一對括號)。若是在同一段內容中須要提取多個字段,那就分屢次匹配便可。

寫在最後

實現了基於正則表達式的提取器後,咱們就完全實現了對任意格式HTTP響應內容的解析,不只限於XML/HTML類型,對於任意基於HTTP協議的的接口,ApiTestEngine均可以適用了。固然,若是接口響應是JSON類型,咱們雖然能夠也使用正則表達式提取,但更建議採用原有的點(.)運算符形式,由於描述更清晰。

至此,ApiTestEngine能夠說是真正意義上實現了,面向任意類型的HTTP協議接口,只須要編寫維護一份YAML用例,便可同時實現接口自動化測試、性能測試、持續集成、線上監控的全測試類型覆蓋!

如今看來,ApiTestEngine的名字與其實際功能有些不大匹配了,是該考慮更名了。

原始連接:debugtalk.com/post/apites…

相關文章
相關標籤/搜索