Java接口自動(dòng)化框架系列07:Web接口自動(dòng)化測(cè)試框架設(shè)計(jì)思路

1.Java web接口自動(dòng)化框架

框架名稱:Java+Maven+httpClients+TestNg+Allure

(因本次只講解java部分,未包括git和jenkins闸度,如果是包括git和jenkins可參考Java自動(dòng)化框架總篇)

框架圖:

框架思路:

2.分析接口

CASB接口參考:

https://10.1.1.104/uim/doc.html

https://10.1.1.104/sem/doc.html

https://10.1.1.104/kms/doc.html

2.1.Post方法(例如查詢角色)

這里需要多收集和了解一些接口退个,可以通過(guò)Chrome工具或MeterSphere去調(diào)用沿腰。

獲取到多個(gè)接口進(jìn)行對(duì)比,例如把所有的用戶權(quán)限的接口執(zhí)行一遍,拿到入?yún)⒑突貐⑦M(jìn)行分析诈乒。

以下舉例:

查詢角色和登錄围肥,都是POST接口剿干。

1.登錄接口地址:/uim/v1/login請(qǐng)求方式:POST請(qǐng)求示例:? ? {"username":"","password":"","ukeySn":"","serverRandom":"","ukeySign":""}返回結(jié)果:{"code":0,"data": {"accessToken":"","expiresDate":"","expiresIn":0,"refreshExpiresDate":"","refreshExpiresIn":0,"refreshToken":"","scope":"","tokenType":""},"msg":"成功"}2.查詢角色:接口地址:/uim/v1/role/list請(qǐng)求方式:POST請(qǐng)求示例:{"page":1,"limit":10,"sidx":"","order":""}響應(yīng)示例:{"code":0,"data": {"currPage":0,"list": [? ? ? ? ? ? {"createTime":"","permissionIdList": [],"permissionList": [? ? ? ? ? ? ? ? ? ? {"childPermissionList": [? ? ? ? ? ? ? ? ? ? ? ? ? ? {"childPermissionList": [? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {}? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ],"createTime":"","parentId":"","parentPermission": {},"permissionId":"","resourceDescribe":"","resourceIcon":"","resourceName":"","resourceOrder":0,"resourceRouter":"","resourceType":0,"resourceUrls":""}? ? ? ? ? ? ? ? ? ? ? ? ],"createTime":"","parentId":"","parentPermission": {},"permissionId":"","resourceDescribe":"","resourceIcon":"","resourceName":"","resourceOrder":0,"resourceRouter":"","resourceType":0,"resourceUrls":""}? ? ? ? ? ? ? ? ],"roleDescribe":"","roleId":"","roleName":""}? ? ? ? ],"pageSize":0,"totalCount":0,"totalPage":0},"msg":"成功"}

2.2.Get方法(例如刪除角色)

請(qǐng)求地址:/uim/v1/role/delete

請(qǐng)求方式:GET

請(qǐng)求參數(shù):id= ? ? ?

響應(yīng)示例:

{

"code": 0,

"data": {},

"msg": "成功"

}

接口都有請(qǐng)求頭信息,輸入?yún)?shù)穆刻,接口請(qǐng)求置尔,輸出參數(shù)

1、輸入?yún)?shù):POST接口氢伟,這里全部都是JSON格式

GET接口榜轿,都是參數(shù)入?yún)?/p>

2、發(fā)送和處理請(qǐng)求

3朵锣、輸出參數(shù):所有CASB的接口谬盐,都是JSON格式

3.選擇工具/語(yǔ)言

這里用到的工具類:可參考0.CASB2.0接口自動(dòng)化培訓(xùn)計(jì)劃.md文檔中的《框架工具類用到的Java基礎(chǔ)知識(shí)》。

3.1.語(yǔ)言選擇

這里選擇Java語(yǔ)言是因?yàn)榧咏饷艿木壒食闲^(guò)插件需要通過(guò)java語(yǔ)言+插件jar包對(duì)數(shù)據(jù)庫(kù)插入數(shù)據(jù)加密和查詢數(shù)據(jù)解密飞傀。

單純的web接口自動(dòng)化,其實(shí)用python或meterSphere學(xué)習(xí)成本更低些诬烹。

Python語(yǔ)言支持testng和allure報(bào)告也更友好一些砸烦。

3.2.針對(duì)接口的工具選取

3.2.1. 發(fā)送請(qǐng)求(HttpClient)

該框架使用的是CloseableHttpClient。

工具類:HttpsClientUtils

這里是我寫的HttpClient工具類绞吁,舉例的Get和Post方法

/**

* 發(fā)送HttpGet請(qǐng)求,不帶請(qǐng)求頭和請(qǐng)求參數(shù)

* @param url 請(qǐng)求地址

* @return doGet(url,null,null)

*/

public ?HttpClientResult doGet(String url) throws Exception {

}

/**

* 發(fā)送HttpGet請(qǐng)求幢痘,帶請(qǐng)求頭和請(qǐng)求參數(shù)

* @param url 請(qǐng)求地址

* @param headers ,params

*/

public ?HttpClientResult doGet(String url,Map<String, String> headers,Map<String,String> params) throws Exception{}

/**

* 發(fā)送POST請(qǐng)求,不帶請(qǐng)求參數(shù)

* @param url 請(qǐng)求地址

* @return doPost(url,headers,null)

*/

public ?HttpClientResult doPost(String url,Map<String, String> headers) throws Exception {

}

/**

* 發(fā)送POST請(qǐng)求,帶請(qǐng)求參數(shù)

* @param url 請(qǐng)求地址

* @param headers 請(qǐng)求頭

* @param jsonStr 請(qǐng)求json

*/

public ?HttpClientResult doPost(String url, Map<String, String> headers,String jsonStr) throws Exception {}

3.2.2.接口的入?yún)?/p>

3.2.2.1.如果入?yún)⒅苯訉懺诖a里掀泳,那么就不需2

3.2.2.2.通過(guò)Excel獲取接口的入?yún)⒉鲄?/p>

那么這里就需要學(xué)習(xí)讀取Excel的工具雪隧,本次框架里介紹的是:阿里的easyexcel

工具類:ExcelUtil

寫入Excel的方法:

/**

* 寫excel

* @param fileName 寫入excel的文件名稱

* @param sheetName

* @param dataList 數(shù)據(jù)

*/

public static void writeExcel(String fileName, String sheetName, List<ApiDataBean> dataList) {}

讀取excel的方法:

/**

* 讀取excel,放入caseDataBean

* @param fileName 讀取excel的文件名稱

* @return datalist

*/

public static List<ApiDataBean> readExcel(String fileName, String sheetName){}

3.2.2.3.入?yún)⑹褂米兞啃枰矃?shù)替換變量

工具類:ParamUtil

調(diào)用:String reqUrl = host + url;

Map<String, String> headers=getHeader(token);

String reqData=paramUtil.getCommonParam(data.getParam());

//發(fā)送請(qǐng)求

HttpsClientUtils httpUtil = new HttpsClientUtils();

HttpClientResult httpResult = httpUtil.doPost(reqUrl, headers,reqData);

/**

* 取公共參數(shù) 并替換參數(shù)西轩,處理${}

* @param param @description 參數(shù)

* @return param

*/

public String getCommonParam(String param) {}

3.2.3.接口的出參解析

3.2.3.1.接口簡(jiǎn)單回參解析,可以直接用Java的JsonPath

參考:?GitHub - json-path/JsonPath: Java JsonPath implementation

3,2.3.2.接口復(fù)雜的回參解析

需要自己編寫(Json解析有4種方法脑沿,我這里選取使用的Gson)

調(diào)用例如:StringroleId = JsonUtil.getTargetValue(resultContent, roleName,"roleName","roleId");/**

? ? * 解析一層json樹結(jié)構(gòu)藕畔,只有JsonObject,獲取第1層json中某個(gè)key的值

? ? * @param jsonString json字符串

? ? * @param dataKey key

? ? */publicstaticStringgsonParserString(StringjsonString,StringdataKey){}/**

? ? * 解析二層json樹結(jié)構(gòu)庄拇,只有JsonObject,獲取第2層json中某個(gè)key的值

? ? * @param jsonString? json字符串

? ? * @param dataKey key

? ? */publicstaticStringgsonParserString_2(StringjsonString,StringdataKey){}/**

? ? * 解析三層樹結(jié)構(gòu)并帶有1個(gè)JsonArray(list),獲取第3層json中列表中第1個(gè)json指定key的值

? ? * @param jsonString json字符串

? ? * @param dataKey (獲取data中l(wèi)ist的里String類型)

? ? */publicstaticStringgsonParserString_3l(StringjsonString,StringdataKey){}/**

? ? * 解析四層樹結(jié)構(gòu)并帶有2個(gè)JsonArray,獲取第4層json列表中指定key的所有值

? ? * @param jsonString json字符串

? ? * @param dataKey (獲取data中l(wèi)ist的里String類型)

? ? *///for (JsonElement element : jsonArray) 遍歷數(shù)據(jù)publicstaticList gsonParserString_4l(StringjsonString,Stringlist1,Stringlist2,StringdataKey){}/**

? ? * 解析三層樹結(jié)構(gòu)并帶有1個(gè)JsonArray(list),第3層json中找到符合key1值的同json中的key2的值

? ? * @param jsonString json字符串

? ? * @param targetKey (獲取data中l(wèi)ist的里String類型)

? ? */publicstaticStringgetTargetValue(StringjsonString,StringsourceName,StringsourceKey,StringtargetKey){}

其他的3種Json處理可參考:?JAVA中的四種JSON解析方式詳解 - 道理我都懂Zz - 博客園

3.3.單一接口調(diào)工具類

3.3.1.POST接口

例如:login

StringloginUrl ="https://10.1.1.104/uim/v1/login";StringjsonStr ="{\"username\":\"YWRtaW4=\",\"password\":\"bGlhblNoaTIwMjA=\"}";//請(qǐng)求頭Map headers=newHashMap<>();? ? headers.put("Content-Type","application/json;charset=UTF-8");//發(fā)送請(qǐng)求HttpsClientUtils httpUtils =newHttpsClientUtils();? ? HttpClientResult result=httpUtils.doPost(loginUrl,headers, jsonStr);

全部代碼:

package com.ciphergateway.server;importcom.ciphergateway.bean.HttpClientResult;importcom.ciphergateway.utils.Base64Util;importcom.ciphergateway.utils.HttpsClientUtils;importcom.ciphergateway.utils.JsonUtil;importcom.ciphergateway.utils.PropertiesUtil;importorg.apache.logging.log4j.LogManager;importorg.apache.logging.log4j.Logger;//import java.util.Base64;importjava.util.HashMap;importjava.util.Map;importjava.util.Properties;publicclassLogin{? ? privatestaticfinalLogger log= LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);/**? ? * 獲取login的token? ? */publicStringgetToken() throws Exception{//獲取配置文件Stringfilename="config.properties";? ? ? ? PropertiesUtil pro=newPropertiesUtil(filename);Stringhost=pro.readProperty("HOST");Stringusername=pro.readProperty("USER_NAME");Stringpassword=pro.readProperty("USER_SECRET");? ? ? ? Base64Util base64=newBase64Util();Stringuser_base64 = base64.getBase64(username);Stringpassword_base64 = base64.getBase64(password);//測(cè)試HTTPSHttpsClientUtils httpUtils =newHttpsClientUtils();StringloginUrl = host+"/uim/v1/login";StringjsonStr ="{\"username\":\""+ user_base64 +"\",\"password\":\""+ password_base64 +"\"}";//System.out.println(jsonStr);//請(qǐng)求頭Map headers=newHashMap<>();? ? ? ? headers.put("Content-Type","application/json;charset=UTF-8");? ? ? ? HttpClientResult httpResult=null;try{? ? ? ? ? ? httpResult = httpUtils.doPost(loginUrl, headers,jsonStr);? ? ? ? }catch(Exception e) {? ? ? ? ? ? e.printStackTrace();? ? ? ? ? ? log.error(e);? ? ? ? }//System.out.println(httpResult.getCode());//System.out.println(httpResult.getContent());intcode=httpResult.getCode();StringresultContent=httpResult.getContent();? ? ? ? log.info(code+" "+resultContent);Stringtoken =JsonUtil.gsonParserString_2(resultContent,"accessToken");returntoken;? ? }/*? ? public static void main(String[] args) throws Exception {

? ? ? ? Login lo=new Login();

? ? ? ? String token=lo.getToken();

? ? ? ? System.out.println(token);

? ? }*/}

3.3.2.GET方法(刪除角色)

StringreqUrl ="https://10.1.1.104/uim/v1/role/delete";Map map_delete =newHashMap<>();? ? map_delete.put("id","1234567890212222");Map headers=newHashMap<>();? ? headers.put("Content-Type","application/json;charset=UTF-8");? ? headers.put("Authorization",token);//發(fā)送請(qǐng)求HttpsClientUtils httpUtils =newHttpsClientUtils();? ? HttpClientResult httpResult = httpUtils.doGet(reqUrl, headers, map_delete);

3.4.斷言(TestNg單元測(cè)試框架)

需要使用TestNg單元測(cè)試框架進(jìn)行批量測(cè)試注服,斷言和初始化數(shù)據(jù)和清理數(shù)據(jù)。3.

批量測(cè)試:testng.xml初始化數(shù)據(jù):@BeforeTest測(cè)試:@Test清理數(shù)據(jù):@AfterTest斷言:Assert例如:1措近、TestNg默認(rèn)的斷言:Assert.assertEquals(code, expectData,data.getDesc());2溶弟、為了異常場(chǎng)景新增的斷言:Assertion.verifyEquals(code, expectData,data.getDesc());

3.5。結(jié)果和報(bào)告展示

3.5.1Excel測(cè)試結(jié)果

備注:dataList_w是List參數(shù)//調(diào)用excel方法寫入數(shù)據(jù)StringexcelFile_result="src/data/testcase/apiData_result.xlsx";? ? ? ? privateStringsheet1="用戶權(quán)限接口用例";? ? ? ? ExcelUtil.writeExcel(excelFile_result,sheet1,dataList_w);

3.5.2.Allure報(bào)告

參考《 Web接口自動(dòng)化Allure報(bào)告的配置和使用》

https://blog.csdn.net/fen_fen/article/details/122020651

4.總結(jié)

4.1.web接口框架使用的工具/框架

序號(hào)工具或框架名版本

1Mavenapache-maven-3.8.1

2httpClienthttpClient 4.5.3

3TestNGTestng 6.11

4Allure測(cè)試報(bào)告Allure 2.13.2

5Git煉石 git

4.2.框架的優(yōu)點(diǎn)

1瞭郑、采用數(shù)據(jù)驅(qū)動(dòng)方式來(lái)解決大量功能重復(fù)性接口的測(cè)試

2辜御、代碼分層

3、針對(duì)返回JSON字符串屈张,采用JSONPath和Gson結(jié)合的模式來(lái)精準(zhǔn)判定JSON的內(nèi)容擒权。

4、可以生成比較直觀的報(bào)告阁谆。

5碳抄、后期可以跟Jenkins持續(xù)集成,執(zhí)行結(jié)果生成測(cè)試報(bào)告并發(fā)送郵件告知相關(guān)人員

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末场绿,一起剝皮案震驚了整個(gè)濱河市剖效,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌焰盗,老刑警劉巖璧尸,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異熬拒,居然都是意外死亡逗宁,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門梦湘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人件甥,你說(shuō)我怎么就攤上這事捌议。” “怎么了引有?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵瓣颅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我譬正,道長(zhǎng)宫补,這世上最難降的妖魔是什么檬姥? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮粉怕,結(jié)果婚禮上健民,老公的妹妹穿的比我還像新娘。我一直安慰自己贫贝,他們只是感情好秉犹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著稚晚,像睡著了一般崇堵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上客燕,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天鸳劳,我揣著相機(jī)與錄音,去河邊找鬼也搓。 笑死赏廓,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的还绘。 我是一名探鬼主播楚昭,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拍顷!你這毒婦竟也來(lái)了抚太?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤昔案,失蹤者是張志新(化名)和其女友劉穎尿贫,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踏揣,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡庆亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捞稿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片又谋。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖娱局,靈堂內(nèi)的尸體忽然破棺而出彰亥,到底是詐尸還是另有隱情,我是刑警寧澤衰齐,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布任斋,位于F島的核電站,受9級(jí)特大地震影響耻涛,放射性物質(zhì)發(fā)生泄漏废酷。R本人自食惡果不足惜瘟檩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望澈蟆。 院中可真熱鬧墨辛,春花似錦、人聲如沸丰介。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)哮幢。三九已至带膀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間橙垢,已是汗流浹背垛叨。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留柜某,地道東北人嗽元。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像喂击,于是被迫代替她去往敵國(guó)和親剂癌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容