檢查數(shù)據(jù)接口返回數(shù)據(jù)合法性

本文章轉(zhuǎn)載于搜狗測試

問題背景:

在測試&部署監(jiān)控過程中,我們常常會遇到外部接口返回數(shù)據(jù)不靠譜的時候。最常見的場合是從某個http獲取如json和xml等結(jié)構(gòu)化的結(jié)果,進行解析并處理,在這時候出現(xiàn)以下這幾種常見類型的錯誤:

(1)整個結(jié)構(gòu)不完整。直接無法解析json/xml。

(2)編碼錯誤,常見的gbk/utf8錯誤

(3)超長數(shù)據(jù)/非法字符。

(4)數(shù)據(jù)類型不匹配。需要是數(shù)字的給了字符串,該是數(shù)組的給了字符串等,對json本身來說沒問題,程序處理就會錯誤或者崩潰。

(5)字段缺失或者為空,這個情況對json本身來說也是沒問題的,處理進程固定要去取這里的字段就會出問題,或者進程本身沒問題,但實際展現(xiàn)出問題。

例如json描述一個商品最近30天的售價,提供一個數(shù)組里有30個數(shù)據(jù)來畫點,json里這個數(shù)組為空,從數(shù)據(jù)格式上來說沒問題,但實際畫點時展現(xiàn)即為空。

截圖是來自一份合作方的數(shù)據(jù),箭頭指向的是上證指數(shù)曲線的點,如果點數(shù)據(jù)完全缺失(為空)則畫曲線的界面會顯示為空。在json結(jié)構(gòu)上則仍然驗證為合法。

解決問題的現(xiàn)狀:

對上述問題,我們有一些簡單的自動化監(jiān)控手段,通過定期抓取http接口再獲取其中內(nèi)容這一步比較簡單,接下來我們會驗證http狀態(tài)碼(200正常,非200認(rèn)為是有問題)和長度,如果過短(例如少于20字節(jié))則認(rèn)為是無效。

還有一些自動化case會先人工看一下接口返回的具體內(nèi)容,然后再作為case檢查點,檢查抓取接口中是否存在固定字符串片段,以此進一步驗證返回結(jié)果的正確性。這里我們?nèi)匀贿M行的是字符串粒度上的檢查。

解決問題思考:

如果只通過字符串的方式檢測長度,這個粒度過于粗糙,難以發(fā)現(xiàn)上述詳細一些問題。檢查固定的字符串片段存在,能部分彌補上述不足,但仍然無法檢查背景中提到的諸如字段缺失的問題。

但是若要檢查字符串完全相同,則要求接口每次返回的數(shù)據(jù)完全相同,和實際應(yīng)用情況不符,維護case難度大。那么,我們的思路就轉(zhuǎn)向如何對數(shù)據(jù)結(jié)構(gòu)體進行檢查。

總的思路出于以下幾條:

1.根據(jù)歷史接口請求結(jié)果作為范本,提取特征作為約束對新數(shù)據(jù)進行檢查。提高工具本身的適用范圍。

2.接口返回的數(shù)據(jù)應(yīng)該可以化為結(jié)構(gòu)體,通過對結(jié)構(gòu)體字段的條件約束來判斷數(shù)據(jù)檢查是否通過。

3.對有些字段內(nèi)容可以進行二次解析,保障其中數(shù)據(jù)的合法性。

4.基于歷史數(shù)據(jù)特征進行統(tǒng)計,輔助對數(shù)據(jù)字段進行正確性檢查,進一步降低維護條件約束的難度。

接下來我們逐步來設(shè)計我們以上思考功能。

解決問題的設(shè)計:

0.用什么代碼?

現(xiàn)在任何一種主流語言都有成熟的json/xml解析庫,幸運的是作為正確性檢查,這個規(guī)模我們基本不需要考慮性能問題。當(dāng)速度不可接受的時候可以考慮多進程分開跑來環(huán)節(jié)壓力。

推薦腳本語言python/php,開發(fā)起來更快一些。作為一個輕量的檢查工具甚至只是個lib,它應(yīng)該盡量簡單,方便使用,方便納入現(xiàn)有的測試框架之中。

1.如何抽取特征?

無論是json還是xml,本質(zhì)上都是樹形結(jié)構(gòu)?;谖覀冏罱K目的是進行驗證的考慮,把json/xml解析為樹是個不錯的主意。既然預(yù)期結(jié)構(gòu)完全相同,那么我們可以依照key,依次遍歷檢查樹的每個節(jié)點,比對被比較object是否一致。

以json為例,我們輸入兩個json字符串,將其轉(zhuǎn)化為object。如果是復(fù)雜結(jié)構(gòu),則再對object進行遞歸比較,如果是int或者string,則按既定規(guī)則比較。

function compare_json($in_json, $diff_json){

$json = new Services_JSON();

$start_object = $json->decode($json_str_from_file);

$diff_object = $json->decode($json_str_diff_from_file);

return compare_all($start_object, $diff_object);

}

compare_all(obj2) 進行遍歷,先判斷類型再進行比較,返回布爾值檢查結(jié)果向上傳遞。

如圖,我們舉個例子,查詢某個小組成員的數(shù)據(jù),根據(jù)json生成的樹

{

"name":"name1",

"date":123,

"members":[

{

"name":"alice",

"level":5,

"lastpost":{

"title":"noname1",

"date":500

}

},

{

"name":"bob",

"level":0,

"lastpost":{

"title":"noname2",

"date":501

}

}

]

}

對應(yīng)的結(jié)構(gòu)


2.約束條件都有哪些類型?

根據(jù)實際應(yīng)用情況的不同,可以按需求調(diào)整。特別是數(shù)組由于數(shù)量一般不一致,可以考慮在非空的條件下只取第一個進行結(jié)構(gòu)驗證,也可以考慮遍歷取每一個節(jié)點進行相同的結(jié)構(gòu)驗證。

在這里舉一些例子作為常見的檢查參考:

(1)根據(jù)key進行遍歷,如果對照的測試數(shù)據(jù)直接取不到key對應(yīng)的object,則認(rèn)為有問題。在取到數(shù)據(jù)的情況下進行比較:

(2)兩邊數(shù)據(jù)類型一致

(3)樣板數(shù)據(jù)非空的情況下,檢查數(shù)據(jù)應(yīng)該非空

(4)樣板數(shù)據(jù)為空,檢查數(shù)據(jù)為非空或空都可以

(5)數(shù)組里的元素個數(shù)應(yīng)該保持一致

(6)如果不是葉子節(jié)點,它下面還有某種結(jié)構(gòu)的話,用相同規(guī)則處理下面的子樹。

3.對其中個別節(jié)點的附加檢查方式:

我們同樣考慮,在一些case的執(zhí)行中,要求對其中一些重要的節(jié)點做出復(fù)雜檢查操作,這些檢查操作是根據(jù)case來的,不能適用到其他case上。最重要的問題是如何定位節(jié)點。

例如上述每條json數(shù)據(jù)中,希望檢查每個level都在5以上… 通過path定位需要一個輔助工具來索引json返回對應(yīng)的數(shù)據(jù)。

對于xpath for json,php有第三方的lib提供了jsonpath來執(zhí)行類似xpath的檢索功能。通過實驗檢查可行,也可以單獨根據(jù)xpath的語法寫一個解析器,但這里不符合我們對快速實現(xiàn)最終檢查目的這個目標(biāo)。是否自己寫lib來支持,取決于工期的長短。

http://goessner.net/articles/JsonPath/

一個簡單的實例,對每個level進行檢查。

//load library

require_once ('lib/JSON.php');

require_once ('lib/jsonpath-0.8.1.php');

$json_newstr ='{"name": "name1", "date": 123, "members": [{"name":"alice", "level": 5, "lastpost": {"title": "noname1", "date": 500}} , {"name":"bob", "level": 0, "lastpost": {"title": "noname2", "date": 501}}]}';

echo"json str: $json_newstr\n";

$json =newServices_JSON(SERVICES_JSON_LOOSE_TYPE);

$start_object = $json->decode($json_newstr);

$result = jsonPath($start_object,"$..members..level");

echo"got all levels...\n";

var_dump($result);

$check_result_ok =true;

foreach($result as $level_to_check){

if($level_to_check <=0){

$check_result_ok =false;

}

}

var_dump($check_result_ok);

運行上述片段對json字符串進行檢查

task start...

json str: {"name":"name1","date":123,"members": [{"name":"alice","level":5,"lastpost": {"title":"noname1","date":500}} , {"name":"bob","level":0,"lastpost": {"title":"noname2","date":501}}]}

got all levels...

array(2) {

[0]=>

int(5)

[1]=>

int(0)

}

bool(false)

task end. run checkfor0time(s)

我們輸出檢查結(jié)果為false,發(fā)現(xiàn)了一條不符合預(yù)期的數(shù)據(jù)。

4. 如何基于歷史特征進行統(tǒng)計?

在以上部分我們了解如何提取特征后,我們可以考慮將其按照結(jié)構(gòu)化保存在mysql里。在前幾步執(zhí)行過程中我們已經(jīng)遍歷了json對應(yīng)object的樹狀結(jié)構(gòu),以及通過xpath等樹狀描述對節(jié)點進行定位。將這幾個步驟組合起來即可:以接口為key,按需要保存若干特征描述,對后續(xù)提取的結(jié)果進行檢查。

以上面的樣例json為例,我們可以保存每次抓取檢查時,/members[]數(shù)組下的元素個數(shù),當(dāng)和歷史平均值波動大于80%時認(rèn)為是有問題報警。

5. 基于字符串的檢查…

除了上述的詳細檢查外,我們依然需要對字符串進行一些檢查,例如編碼、總長度和結(jié)構(gòu)完整性。最后一點比較簡單,考慮調(diào)用lib時parse失敗,如果失敗說明json/xml結(jié)構(gòu)不完整,保存現(xiàn)場供人工查看,調(diào)整case。

以上就是關(guān)于數(shù)據(jù)接口檢查類的自動化測試思路,在設(shè)計上我們考慮到現(xiàn)在一些自動化監(jiān)控/測試實踐中遇到的問題,和趨向最新機器學(xué)習(xí)思路提取特征的想法提出的想法。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,715評論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,896評論 18 399
  • 早晨一出門,能感覺到空氣中的酸味,猶豫了一下,是否回家。最后,也不想騎車,坐公交去了中塢公園。那里空氣好些,站樁一...
    邵清清靜閱讀 410評論 2 4
  • 為什么我們一定要學(xué)會寫作? 實現(xiàn)財富自由很重要的方法就是:把自己同一份時間銷售很多次,比如歌手,作者。 而寫作是把...
    Bog5d閱讀 243評論 0 0
  • “啪”一記耳光狠狠甩在劉文靜臉上,劉文靜呆住了,一臉震驚的看著梁海洋,“你,你敢打我?” “打你又怎樣!”梁海洋太...
    夜雨縉云閱讀 1,065評論 2 37

友情鏈接更多精彩內(nèi)容