日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java接口自动化Excel占位符_基于maven+java+TestNG+httpclient+poi+jsonpath+ExtentReport的接口自动化测试框架...

發布時間:2023/12/2 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java接口自动化Excel占位符_基于maven+java+TestNG+httpclient+poi+jsonpath+ExtentReport的接口自动化测试框架... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

接口自動化框架

項目說明

本框架是一套基于maven+java+TestNG+httpclient+poi+jsonpath+ExtentReport而設計的數據驅動接口自動化測試框架,TestNG 作為執行器,poi用于讀取存放于excel的接口用例,jsonPath用于校驗返回值,以及提取返回值。本框架無需你使用代碼編寫用例,在excel中即可進行接口用例編寫,接口依賴關聯,接口斷言,控制用例的運行。

技術棧

maven

java

TestNG

httpclient

poi

jsonpath

ExtentReport

環境部署

安裝jdk8,并配置好環境變量

maven中直接導入項目工程包,導入成功后,maven會自動下載當前項目的所有依賴包

代碼設計與功能說明

1、定義運行配置文件 api-config.xml

api請求根路徑、請求頭及初始化參數值可以在api-config上進行配置。

rootUrl: 必須的配置,api的根路徑,在調用api時用于拼接,配置后,會在自動添加到用例中的url的前綴中。

headers: 非必須配置,配置后在調用api時會將對應的name:value值設置到所有請求的請求頭中header-name:header-value。

params:非必須配置,公共參數,通常放置初始化配置數據,所有用例執行前,會將params下所有的param配置進行讀取并存儲到公共參數池中,在用例執行時,使用特定的關鍵字(${param_name})可以獲取。具體如下:

api-config.xml配置信息

http://127.0.0.1:12306

接口自動化測試報告demo

2、測試用例的設計

測試用例以excel格式的文件保存,除表頭外,一行代表一個api用例。執行時會依次從左到右,從上到下執行。case/api-data.xls測試用例的數據格式如下:

run:標記為‘Y’時,該行數據會被讀取執行;標記為‘N’則不被執行

description:該用例描述,在報告中體現。

method:該api測試用例的請求方法。

url:該api測試用例的請求路徑。

說明:

若配置文件(api-config.xml)中rootUrl為:http://127.0.0.1:12306 ,url的值為:/parkinside ,框架執行的時候會根據配置文件中rootUrl進行自動拼接為:http://127.0.0.1:12306/parkinside 。若url填寫為http作為前綴的值如:http://127.0.0.1:12306/parkinside 將不會進行拼接。

param:請求方法為post時,body的內容(暫只支持json,不支持xml)

verify:對于api請求response數據的驗證(可使用jsonPath進行校驗)。校驗多個使用“;”進行隔開。

若verify填寫值為:$.username=wuya;$.userID=22 ,則會校驗返回值中$.username的值為wuya,$.userID的值為22,只要有一個校驗錯誤,后面的其他校驗項將停止校驗。

save:使用jsonPath對response的數據進行提取存儲。

說明:若save值為:id=$.userId;age=$.age ,接口實際返回內容為:{"username":"chenwx","userId":"1000","age":"18"},則接口執行完成后,會將公共參數userId的值存儲為1000,age存儲為18。公共參數可在后面的用例中進行使用。

公共關聯池中的公共參數使用

測試用例excel表中可以使用‘${param_name}’占位符,在執行過程中如果判斷含有占位符,則會將該值替換為公共參數里面的值,如果找不到將會報錯。具體使用格式如下:

{

"token":"${g_token}",

"vpl":"AJ3585"

}

3、函數助手

測試用例excel表中可以使用‘__funcName(args)’占位符,在執行過程中如果判斷含有該占位符,且funcName存在,則會執行相應的函數后進行替換。部分函數說明如下:

__random(param1,param2):隨機生成一個定長的字符串(不含中文)。param1:長度(非必填,默認為6),param2:純數字標識(非必填,默認為false)。

__randomText(param1): 隨機生成一個定長的字符串(含中文)。param1:長度(非必填,默認為6)

__date(param1): 生成執行該函數時的時間格式化字符串。param1為轉換的格式,默認為生成當前13位時間戳。

具體使用格式如下:

{

"drivers":"張三",

"cmsuer":"__random(8,false)",

"time":"__date()"

}

函數random執行時會產生8位長度的隨機字符串,并傳給變量cmsuer;函數date在執行時,會產生一個13位的時間戳,并傳給變量time。

4、測試執行主程序

package test.com.sen.api;

import com.alibaba.fastjson.JSON;

import com.sen.api.beans.ApiDataBean;

import com.sen.api.configs.ApiConfig;

import com.sen.api.excepions.ErrorRespStatusException;

import com.sen.api.listeners.AutoTestListener;

import com.sen.api.listeners.RetryListener;

import com.sen.api.utils.*;

import org.apache.http.Header;

import org.apache.http.HttpEntity;

import org.apache.http.HttpResponse;

import org.apache.http.client.HttpClient;

import org.apache.http.client.methods.*;

import org.apache.http.entity.StringEntity;

import org.apache.http.entity.mime.MultipartEntity;

import org.apache.http.entity.mime.content.FileBody;

import org.apache.http.entity.mime.content.StringBody;

import org.apache.http.message.BasicHeader;

import org.apache.http.params.CoreConnectionPNames;

import org.apache.http.util.EntityUtils;

import org.dom4j.DocumentException;

import org.testng.Assert;

import org.testng.ITestContext;

import org.testng.annotations.*;

import org.testng.annotations.Optional;

import java.io.File;

import java.io.InputStream;

import java.io.UnsupportedEncodingException;

import java.nio.file.Paths;

import java.util.*;

import java.util.regex.Matcher;

@Listeners({ AutoTestListener.class, RetryListener.class })

public class ApiTest extends TestBase {

/**

* api請求跟路徑

*/

private static String rootUrl;

/**

* 跟路徑是否以‘/’結尾

*/

private static boolean rooUrlEndWithSlash = false;

/**

* 所有公共header,會在發送請求的時候添加到http header上

*/

private static Header[] publicHeaders;

/**

* 是否使用form-data傳參 會在post與put方法封裝請求參數用到

*/

private static boolean requestByFormData = false;

/**

* 配置

*/

private static ApiConfig apiConfig;

/**

* 所有api測試用例數據

*/

protected List dataList = new ArrayList();

private static HttpClient client;

/**

* 初始化測試數據

*

* @throws Exception

*/

@Parameters("envName")

@BeforeSuite

public void init(@Optional("api-config.xml") String envName) throws Exception {

String configFilePath = Paths.get(System.getProperty("user.dir"), envName).toString();

ReportUtil.log("api config path:" + configFilePath);

apiConfig = new ApiConfig(configFilePath);

// 獲取基礎數據

rootUrl = apiConfig.getRootUrl();

rooUrlEndWithSlash = rootUrl.endsWith("/");

Map params = apiConfig.getParams();

setSaveDates(params);

List headers = new ArrayList();

apiConfig.getHeaders().forEach((key, value) -> {

Header header = new BasicHeader(key, value);

if(!requestByFormData && key.equalsIgnoreCase("content-type") && value.toLowerCase().contains("form-data")){

requestByFormData=true;

}

headers.add(header);

});

publicHeaders = headers.toArray(new Header[headers.size()]);

client = new SSLClient();

client.getParams().setParameter(

CoreConnectionPNames.CONNECTION_TIMEOUT, 60000); // 請求超時

client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 60000); // 讀取超時

}

@Parameters({ "excelPath", "sheetName" })

@BeforeTest

public void readData(@Optional("case/api-data.xls") String excelPath, @Optional("Sheet1") String sheetName) throws DocumentException {

dataList = readExcelData(ApiDataBean.class, excelPath.split(";"),

sheetName.split(";"));

}

/**

* 過濾數據,run標記為Y的執行。

*

* @return

* @throws DocumentException

*/

@DataProvider(name = "apiDatas")

public Iterator getApiData(ITestContext context)

throws DocumentException {

List dataProvider = new ArrayList();

for (ApiDataBean data : dataList) {

//poi解析處理Excel表時,若單元格中的布爾值為Y或者true,則解析到的布爾值為true;若單元格中的布爾值為false或者其他值或者為空,則解析到的布爾值為false

if (data.isRun()) {

dataProvider.add(new Object[] { data });

}

}

return dataProvider.iterator();

}

@Test(dataProvider = "apiDatas")

public void apiTest(ApiDataBean apiDataBean) throws Exception {

ReportUtil.log("--- test start ---");

if (apiDataBean.getSleep() > 0) {

// sleep休眠時間大于0的情況下進行暫停休眠

ReportUtil.log(String.format("sleep %s seconds",

apiDataBean.getSleep()));

Thread.sleep(apiDataBean.getSleep() * 1000);

}

String apiParam = buildRequestParam(apiDataBean);

// 封裝請求方法

HttpUriRequest method = parseHttpRequest(apiDataBean.getUrl(),

apiDataBean.getMethod(), apiParam);

String responseData;

try {

// 執行

HttpResponse response = client.execute(method);

int responseStatus = response.getStatusLine().getStatusCode();

ReportUtil.log("返回狀態碼:"+responseStatus);

if (apiDataBean.getStatus()!= 0) {

Assert.assertEquals(responseStatus, apiDataBean.getStatus(),

"返回狀態碼與預期不符合!");

}

HttpEntity respEntity = response.getEntity();

Header respContentType = response.getFirstHeader("Content-Type");

if (respContentType != null && respContentType.getValue() != null

&& (respContentType.getValue().contains("download") || respContentType.getValue().contains("octet-stream"))) {

String conDisposition = response.getFirstHeader(

"Content-disposition").getValue();

String fileType = conDisposition.substring(

conDisposition.lastIndexOf("."),

conDisposition.length());

String filePath = "download/" + RandomUtil.getRandom(8, false)

+ fileType;

InputStream is = response.getEntity().getContent();

Assert.assertTrue(FileUtil.writeFile(is, filePath), "下載文件失敗。");

// 將下載文件的路徑放到{"filePath":"xxxxx"}進行返回

responseData = "{\"filePath\":\"" + filePath + "\"}";

} else {

responseData=EntityUtils.toString(respEntity, "UTF-8");

}

} catch (Exception e) {

throw e;

} finally {

method.abort();

}

// 輸出返回數據log

ReportUtil.log("resp:" + responseData);

// 驗證預期信息

verifyResult(responseData, apiDataBean.getVerify(),

apiDataBean.isContains());

// 對返回結果進行提取保存。

saveResult(responseData, apiDataBean.getSave());

}

private String buildRequestParam(ApiDataBean apiDataBean) {

// 分析處理預參數 (函數生成的參數)

String preParam = buildParam(apiDataBean.getPreParam());

savePreParam(preParam);// 保存預存參數 用于后面接口參數中使用和接口返回驗證中

// 處理參數

String apiParam = buildParam(apiDataBean.getParam());

return apiParam;

}

/**

* 封裝請求方法

*

* @param url

* 請求路徑

* @param method

* 請求方法

* @param param

* 請求參數

* @return 請求方法

* @throws UnsupportedEncodingException

*/

private HttpUriRequest parseHttpRequest(String url, String method, String param) throws UnsupportedEncodingException {

// 處理url

url = parseUrl(url);

ReportUtil.log("method:" + method);

ReportUtil.log("url:" + url);

ReportUtil.log("param:" + param.replace("\r\n", "").replace("\n", ""));

//upload表示上傳,也是使用post進行請求

if ("post".equalsIgnoreCase(method) || "upload".equalsIgnoreCase(method)) {

// 封裝post方法

HttpPost postMethod = new HttpPost(url);

postMethod.setHeaders(publicHeaders);

//如果請求頭的content-type的值包含form-data 或者 請求方法為upload(上傳)時采用MultipartEntity形式

HttpEntity entity = parseEntity(param,requestByFormData || "upload".equalsIgnoreCase(method));

postMethod.setEntity(entity);

return postMethod;

} else if ("put".equalsIgnoreCase(method)) {

// 封裝put方法

HttpPut putMethod = new HttpPut(url);

putMethod.setHeaders(publicHeaders);

HttpEntity entity = parseEntity(param,requestByFormData );

putMethod.setEntity(entity);

return putMethod;

} else if ("delete".equalsIgnoreCase(method)) {

// 封裝delete方法

HttpDelete deleteMethod = new HttpDelete(url);

deleteMethod.setHeaders(publicHeaders);

return deleteMethod;

} else {

// 封裝get方法

HttpGet getMethod = new HttpGet(url);

getMethod.setHeaders(publicHeaders);

return getMethod;

}

}

/**

* 格式化url,替換路徑參數等。

*

* @param shortUrl

* @return

*/

private String parseUrl(String shortUrl) {

// 替換url中的參數

shortUrl = getCommonParam(shortUrl);

if (shortUrl.startsWith("http")) {

return shortUrl;

}

if (rooUrlEndWithSlash == shortUrl.startsWith("/")) {

if (rooUrlEndWithSlash) {

shortUrl = shortUrl.replaceFirst("/", "");

} else {

shortUrl = "/" + shortUrl;

}

}

return rootUrl + shortUrl;

}

/**

* 格式化參數,如果是from-data格式則將參數封裝到MultipartEntity否則封裝到StringEntity

* @param param 參數

* @param formData 是否使用form-data格式

* @return

* @throws UnsupportedEncodingException

*/

private HttpEntity parseEntity(String param,boolean formData) throws UnsupportedEncodingException{

if(formData){

Map paramMap = JSON.parseObject(param,

HashMap.class);

MultipartEntity multiEntity = new MultipartEntity();

for (String key : paramMap.keySet()) {

String value = paramMap.get(key);

Matcher m = funPattern.matcher(value);

if (m.matches() && m.group(1).equals("bodyfile")) {

value = m.group(2);

multiEntity.addPart(key, new FileBody(new File(value)));

} else {

multiEntity.addPart(key, new StringBody(paramMap.get(key)));

}

}

return multiEntity;

}else{

return new StringEntity(param, "UTF-8");

}

}

}

5、測試總執行器testng.xml(收集測試用例,批量執行并生成測試報告)

6、測試運行方式

IDEA工具直接執行testng.xml(以testng形式運行)即可(IDEA工具需要先裝好testng插件)

maven執行:根目錄下,執行 mvn test

7、測試報告呈現

testng.xml執行可視化報告:${workspace}/test-output/index.html

maven執行報告:${workspace}/target/test-output/index.html

總結

以上是生活随笔為你收集整理的java接口自动化Excel占位符_基于maven+java+TestNG+httpclient+poi+jsonpath+ExtentReport的接口自动化测试框架...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩人妻无码精品久久免费 | 夜夜草av | 亚洲av无码成人精品国产 | 伊人黄网 | 国产91精品高潮白浆喷水 | 亚洲午码| 国产噜噜噜 | 日韩啪啪网站 | 一卡二卡三卡在线 | 羞羞动漫免费观看 | 李丽珍裸体午夜理伦片 | 亚洲色吧 | 无码内射中文字幕岛国片 | 嫩草嫩草嫩草嫩草嫩草嫩草 | 精品无码国产污污污在线观看 | 欧美丰满bbw| 乳女教师の诱惑julia | 伊人网视频在线 | 婷婷深爱 | 色网在线看 | 国产亚洲视频在线 | 国产中文字字幕乱码无限 | 欧美日韩亚洲视频 | 亚洲精品入口 | 九九精品视频在线观看 | 国产一区二区视频免费 | 日本精品一区二区三区四区的功能 | 免费看黄色的视频 | 久久噜噜噜 | 好男人香蕉影院 | 精品国产自在精品国产精小说 | 在线观看免费看片 | 中文字幕第100页 | 中文字幕日韩视频 | 一区二区三区四区亚洲 | 日本激情一区二区 | 欧美丰满一区二区免费视频 | 亚洲自拍图片 | 亚洲两性 | 日韩在线免费视频观看 | 五个女闺蜜把我玩到尿失禁 | 精品乱码久久久久久中文字幕 | 国产第5页 | 免费视频国产 | 一区二区视频免费看 | 少妇三级| 少妇三级全黄 | 欧美视频精品 | 亚洲调教| 熟女高潮一区二区三区 | 日韩一区二区高清 | 国产一区二区三区在线视频 | 精品人妻伦一二三区久 | 成人国产在线视频 | 蜜桃视频无码区在线观看 | 一级二级三级黄色片 | 超碰97在线资源 | 青青草在线观看视频 | 国产精品96久久久久久 | 男女啪啪国产 | 女人18片毛片60分钟 | 亚洲AV无码国产精品午夜字幕 | 香蕉视频污在线观看 | 亚洲欧美激情一区二区三区 | 国产欧美日韩免费 | 大地资源中文第三页 | 日韩av在线网站 | 人妻与黑人一区二区三区 | 亚洲色鬼| 亚洲欧洲精品成人久久奇米网 | 久久九九国产视频 | 国产成人自拍视频在线观看 | 日韩黄色影院 | 中文字幕99 | 色鬼久久 | 亚洲精品国产99 | 日本一区免费 | 欧美日韩一二区 | 疯狂揉花蒂控制高潮h | 在线成人av| 山村大伦淫第1部分阅读小说 | 国产成人+综合亚洲+天堂 | 色窝窝无码一区二区三区成人网站 | 久久久精品一区二区三区 | 一级片啪啪| av视屏在线 | 高跟鞋丝袜猛烈xxxx | 超碰69| 另类小说婷婷 | 欧美偷拍一区二区三区 | 国产69精品久久久 | 亚洲中文一区二区三区 | 久久久久久婷婷 | 成人福利一区二区三区 | 欧美精品一区二区三 | 欧美视频精品 | 天天操操 | 一级少妇精品久久久久久久 | 国产欧美日韩高清 |