接口自动化框架
项目说明
- 本框架是一套基于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
5、测试总执行器testng.xml(收集测试用例,批量执行并生成测试报告)
6、测试运行方式
- IDEA工具直接执行testng.xml(以testng形式运行)即可(IDEA工具需要先装好testng插件)
- maven执行:根目录下,执行 mvn test