You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
greatwall/ApiTest.java

303 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<ApiDataBean> dataList = new ArrayList<ApiDataBean>();
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("/");
// 读取 param并将值保存到公共数据map
Map<String, String> params = apiConfig.getParams();
setSaveDates(params);
List<Header> headers = new ArrayList<Header>();
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") //注解中用name给这个dataprovider命名。
public Iterator<Object[]> getApiData(ITestContext context)
throws DocumentException {
List<Object[]> dataProvider = new ArrayList<Object[]>();
for (ApiDataBean data : dataList) {
if (data.isRun()) {
dataProvider.add(new Object[] { data });
}
}
return dataProvider.iterator();
}
@Test(dataProvider = "apiDatas") //接收 名为apiDatas的dataProvider
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(),
"返回状态码与预期不符合!");
}
// else {
// // 非2开头状态码为异常请求抛异常后会进行重跑
// if (200 > responseStatus || responseStatus >= 300) {
// ReportUtil.log("返回状态码非200开头"+EntityUtils.toString(response.getEntity(), "UTF-8"));
// throw new ErrorRespStatusException("返回状态码异常:"
// + responseStatus);
// }
// }
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 = DecodeUtil.decodeUnicode(EntityUtils
// .toString(respEntity));
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<String, String> 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");
}
}
}