本次介绍的框架使用“聚合数据”的免费API作为实例进行框架介绍,在介绍框架搭建前,可以先注册一个聚合数据账号进行实操。
一:聚合数据的注册:
1、百度搜索“聚合数据”,进入到聚合数据官网注册个账号。
2、注册完账号后,点击【API】导航即可选用免费的试用接口
3、选用想用的API分类,本次框架以【新闻头条】为例
至此就完成了接口申请,可以在【数据中心】->我的API中查看接口的信息,后边的框架介绍也是基于该接口API进行接口测试
二:测试用例的设计
测试用例的设计巧妙之处:
1、参照了Jmeter的参数化方式,将需要参数化的数据用${}包裹起来,后边在解析Excel时,对${}包裹起来的数据,用正则表达式等技术手段替换成实际环境变量的数据,从而实现了参数化设计
2、有一个提取表达式列,通过编写每个接口的JSON提取表达式,后边在解析Excel时,对接口执行后的响应数据用该表达式提取出来,保存到环境变量,如果某些接口需要前置接口的响应数据,我们就可以从环境变量中获取该数据出来,从而解决了接口关联的问题。
3、有一个数据库断言列,由于接口通常需要与数据库操作关联起来,那么通过数据库断言,可以使接口测试结果更加准确稳定。
接下来就进行实际框架搭建了。
一:首先在pom.xml中引入RestAssured、Testng、EasyPOI、fastJson依赖
<!--RestAssured依赖--> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <version>4.2.0</version> <scope>test</scope> </dependency> <!--Testng依赖--> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.0.0</version> <scope>test</scope> </dependency> <!--easyPoi依赖,有两个坐标--> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-annotation</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>cn.afterturn</groupId> <artifactId>easypoi-base</artifactId> <version>4.2.0</version> </dependency> <!--fastJson依赖--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.70</version> </dependency>
本次框架主要包:
common包:存放测试用例的基类,用于封装测试用例的共性操作
config包:存放项目的配置信息,像项目的域名信息、测试用例Excel路径等会在此处配置
enties包:存放项目的实体类
testcases包:存放测试用例
utils包:存放项目的工具类
二:我们现在先来解决测试用例的读取操作。
1、在src/test目录下新建一个resources资源目录,将测试用例放到该目录下
2、在entries包下新建一个CaseInfo实体类,实体类属性编写我们Excel测试用例所有列信息,每个属性用@Excel注解标注,该注解主要是EasyPOI可以用来映射对象属性信息,注意:@Excel里的name信息要与表头字段完全一致,否则无法映射。然后每个属性添加getter、setter方法,最后再添加一个toString方法。
package com.lrc.entries; import cn.afterturn.easypoi.excel.annotation.Excel; /** * @param * @author lrc * @create 2022/1/9 * @return * @description **/ public class CaseInfo { @Excel(name = "序号(caseId)") private int caseId; @Excel(name = "接口模块(interface)") private String interfaceName; @Excel(name = "用例标题(title)") private String title; @Excel(name = "请求头(requestHeader)") private String requestHeader; @Excel(name = "请求方式(method)") private String method; @Excel(name = "接口地址(url)") private String url; @Excel(name = "参数输入(inputParams)") private String inputParams; @Excel(name = "期望返回结果(expected)") private String expected; @Excel(name = "数据库断言") private String dbAssert; @Excel(name="提取表达式(extractExper)") private String extractExper; public int getCaseId() { return caseId; } public void setCaseId(int caseId) { this.caseId = caseId; } public String getInterfaceName() { return interfaceName; } public void setInterfaceName(String interfaceName) { this.interfaceName = interfaceName; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getRequestHeader() { return requestHeader; } public void setRequestHeader(String requestHeader) { this.requestHeader = requestHeader; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getInputParams() { return inputParams; } public void setInputParams(String inputParams) { this.inputParams = inputParams; } public String getExpected() { return expected; } public void setExpected(String expected) { this.expected = expected; } public String getDbAssert() { return dbAssert; } public void setDbAssert(String dbAssert) { this.dbAssert = dbAssert; } public String getExtractExper() { return extractExper; } public void setExtractExper(String extractExper) { this.extractExper = extractExper; } @Override public String toString() { return "CaseInfo{" + "caseId=" + caseId + ", interfaceName='" + interfaceName + '\'' + ", title='" + title + '\'' + ", requestHeader='" + requestHeader + '\'' + ", method='" + method + '\'' + ", url='" + url + '\'' + ", inputParams='" + inputParams + '\'' + ", expected='" + expected + '\'' + ", dbAssert='" + dbAssert + '\'' + ", extractExper='" + extractExper + '\'' + '}'; } }
3、在config包下新建Contants类,填写项目的基本配置信息
package com.lrc.config; /** * @param * @author lrc * @create 2022/1/9 * @return * @description 项目常规信息配置类 **/ public class Contants { //项目访问地址 public static final String PROJECT_URL="v.juhe.cn"; //项目BASEURI地址 public static final String BASE_URL="http://"+PROJECT_URL; //测试用例路径 public static final String EXCEL_PATH="src\\test\\resources\\api_testcases.xls"; //账号数据的Key,此处的key是自己申请聚合数据账号后得到的key public static final String KEY="xxxxx"; }
4、在utils包下新建POI操作类EasyPoiExcelUtil,用于解析Excel测试用例
package com.lrc.utils; import cn.afterturn.easypoi.excel.ExcelImportUtil; import cn.afterturn.easypoi.excel.entity.ImportParams; import com.lrc.config.Contants; import com.lrc.entries.CaseInfo; import java.io.File; import java.util.List; /** * @param * @author lrc * @create 2022/1/9 * @return * @description Excel解析工具类 **/ public class EasyPoiExcelUtil { /** * 使用EasyPOI读取Excel数据 * @return 用例list集合 * 获取Excel里的所有行 */ public static List<CaseInfo> readExcel(int num){ //读取测试用例 File file=new File(Contants.EXCEL_PATH); //读取和导入Excel的参数配置 ImportParams params=new ImportParams(); params.setStartSheetIndex(num); //读取测试用例整合成每条用例对象集合 List<CaseInfo> cases = ExcelImportUtil.importExcel(file, CaseInfo.class, params); return cases; } /** * 使用EasyPOI读取Excel数据 * @return 用例list集合 * 获取Excel里的指定行 */ public static List<CaseInfo> readExcelPart(int num,int startNum,int readRows){ //读取测试用例 File file=new File(Contants.EXCEL_PATH); //读取和导入Excel的参数配置 ImportParams params=new ImportParams(); //读取指定页的Sheet params.setStartSheetIndex(num); //指定从第几行开始读取 params.setStartRows(startNum); //指定读取几行数据 params.setReadRows(readRows); //读取测试用例整合成每条用例对象集合 List<CaseInfo> cases = ExcelImportUtil.importExcel(file, CaseInfo.class, params); return cases; } /** * 使用EasyPOI读取Excel数据 * @return 用例list集合 * 从指定行开始读取下面全部用例 */ public static List<CaseInfo> readExcelPart(int num,int startNum){ //读取测试用例 File file=new File(Contants.EXCEL_PATH); //读取和导入Excel的参数配置 ImportParams params=new ImportParams(); //读取指定页的Sheet params.setStartSheetIndex(num); //指定从第几行开始读取 params.setStartRows(startNum); //读取测试用例整合成每条用例对象集合 List<CaseInfo> cases = ExcelImportUtil.importExcel(file, CaseInfo.class, params); return cases; } }
5、我们在testcases包下新建一个Test01类测试下是否能够解析Excel
package com.lrc.testcases; import com.lrc.entries.CaseInfo; import com.lrc.utils.EasyPoiExcelUtil; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.List; /** * @param * @author lrc * @create 2022/1/9 * @return * @description **/ public class Test01 { @Test(dataProvider = "readCases") public void test01(CaseInfo caseInfo){ System.out.println(caseInfo); } @DataProvider public Object[] readCases(){ List<CaseInfo> listDatas = EasyPoiExcelUtil.readExcel(0); return listDatas.toArray(); } }
执行Test01结果,成功读取了当前Excel中编写的4条用例:
自此,Excel用例的读取操作已经完美解决了。
三:接下来讲接口的通用常规操作封装到common包下的BaseTest类中:
1、首先在config包下新建一个Environment类,作为环境变量的接收传递类
package com.lrc.config; import java.util.HashMap; import java.util.Map; /** * @param * @author lrc * @create 2022/1/9 * @return * @description 主要用于全局管理环境变量,模拟Jmeter变量存储操作 **/ public class Environment { //声明并定义一个map(类似于JMeter的环境变量) public static Map<String,Object> envMap = new HashMap<String, Object>(); }
2、在BaseTest中编写测试用例的共性操作方法:
package com.lrc.common; import com.alibaba.fastjson.JSONObject; import com.lrc.config.Contants; import com.lrc.config.Environment; import com.lrc.entries.CaseInfo; import com.lrc.utils.JDBCUtils; import io.restassured.RestAssured; import io.restassured.config.JsonConfig; import io.restassured.path.json.config.JsonPathConfig; import io.restassured.response.Response; import org.testng.Assert; import org.testng.annotations.BeforeSuite; import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @param * @author lrc * @create 2022/1/9 * @return * @description **/ public class BaseTest { @BeforeSuite public void beforeMethod(){ //把json小数的返回类型配置成BigDecimal类型,通过此配置,可以使得我们在断言小数类型的时候保持数据类型一致,避免了因数据类型不一致而导致断言不通过的情况 RestAssured.config = RestAssured.config().jsonConfig(JsonConfig.jsonConfig().numberReturnType(JsonPathConfig.NumberReturnType.BIG_DECIMAL)); //REST-assured基础 baseurl设置 RestAssured.baseURI= Contants.BASE_URL; } /** * 封装所有请求类型 * @param caseInfo 测试用例对象 * @return response响应对象 */ public static Response request(CaseInfo caseInfo){ //读取测试用例的请求头 String requestHeaders=caseInfo.getRequestHeader(); //将请求头转为map类型数据 Map requestHeadersMap= JSONObject.parseObject(requestHeaders); //读取测试用例的url String url=caseInfo.getUrl(); //读取测试用例的body输入参数 String params=caseInfo.getInputParams(); //读取测试用例的请求方式 String method=caseInfo.getMethod(); //封装请求方法 Response response=null; if ("get".equalsIgnoreCase(method)) { response = RestAssured.given().log().all().headers(requestHeadersMap).when().get(url).then().log().all().extract().response(); } else if ("post".equalsIgnoreCase(method)) { response = RestAssured.given().log().all().headers(requestHeadersMap).body(params).when().post(url).then().log().all().extract().response(); } else if ("put".equalsIgnoreCase(method)) { response = RestAssured.given().log().all().headers(requestHeadersMap).body(params).when().post(url).then().log().all().extract().response(); } return response; } /** * 响应断言 * @param res 实际响应结果 * @param caseInfo 请求数据(实体类) */ public void assertResponse(Response res,CaseInfo caseInfo){ String expected = caseInfo.getExpected(); if(expected != null) { //转成Map Map<String, Object> expectedMap = JSONObject.parseObject(expected); Set<String> allKeySet = expectedMap.keySet(); for (String key : allKeySet) { //获取实际响应结果 Object actualResult = res.jsonPath().get(key); //获取期望结果 Object expectedResult = expectedMap.get(key); Assert.assertEquals(actualResult, expectedResult); } } } /** * 数据库断言统一封装 * @param caseInfo 用例数据 */ public void assertDB(CaseInfo caseInfo){ String dbAssertInfo = caseInfo.getDbAssert(); if(dbAssertInfo != null) { Map<String, Object> mapDbAssert = JSONObject.parseObject(dbAssertInfo); Set<String> allKeys = mapDbAssert.keySet(); for (String key : allKeys) { //key为对应要执行的sql语句 Object dbActual = JDBCUtils.querySingleData(key); //根据数据库中读取实际返回类型做判断 //1、Long类型 if(dbActual instanceof Long){ Integer dbExpected = (Integer) mapDbAssert.get(key); Long expected = dbExpected.longValue(); Assert.assertEquals(dbActual, expected); }else { Object expected = mapDbAssert.get(key); Assert.assertEquals(dbActual, expected); } } } } /** * 通过【提取表达式】将对应响应值保存到环境变量中 * @param res 响应信息 * @param caseInfo 实体类对象 */ public void extractToEnvironment(Response res, CaseInfo caseInfo){ String extractStr = caseInfo.getExtractExper(); if(extractStr != null) { //把提取表达式转成Map Map<String, Object> map = JSONObject.parseObject(extractStr); Set<String> allKeySets = map.keySet(); for (String key : allKeySets) { //key为变量名,value是为提取的gpath表达式 Object value = map.get(key); Object actualValue = res.jsonPath().get((String) value); //将对应的键和值保存到环境变量中 Environment.envMap.put(key, actualValue); } } } /** * 正则替换功能,比如: * 原始字符串 { * key=${key} * } * 替换为 * { * key=xxxx(自己账号生成的key) * } * xxxx 为环境变量中key变量名对应的变量值 * @param orgStr 源字符串 * @return */ public String regexReplace(String orgStr){ if(orgStr != null) { //匹配器 Pattern pattern = Pattern.compile("\\$\\{(.*?)\\}"); //匹配对象 Matcher matcher = pattern.matcher(orgStr); String result = orgStr; //循环遍历匹配对象 while (matcher.find()) { //获取整个匹配正则的字符串 ${key} String allFindStr = matcher.group(0); //找到${XXX}内部的匹配的字符串 key String innerStr = matcher.group(1); //找到key:xxxx //具体的要替换的值(从环境变量中去找到的) Object replaceValue = Environment.envMap.get(innerStr); //要替换${key} --> xxxx result = result.replace(allFindStr, replaceValue + ""); } return result; }else{ return orgStr; } } /** * 整条用例数据的参数化替换,只要在对应的用例数据里面有${}包裹起来的数据,那么就会从环境变量中找,如果找到的话就去替换,否则不会 * @param caseInfo */ public CaseInfo paramsReplace(CaseInfo caseInfo){ //1、请求头 String requestHeader = caseInfo.getRequestHeader(); caseInfo.setRequestHeader(regexReplace(requestHeader)); //2、接口地址 String url = caseInfo.getUrl(); caseInfo.setUrl(regexReplace(url)); //3、参数输入 String inputParams = caseInfo.getInputParams(); caseInfo.setInputParams(regexReplace(inputParams)); //4、期望结果 String expected = caseInfo.getExpected(); caseInfo.setExpected(regexReplace(expected)); return caseInfo; } }
自此,我们的BaseTest已经封装完毕,后边我们每一个测试类都继承该BaseTest类,很大程度降低了代码了耦合度,接下来,我们在testcases包下新建一个Test02测试类,试下发起请求是否成功:
package com.lrc.testcases; import com.lrc.common.BaseTest; import com.lrc.config.Contants; import com.lrc.config.Environment; import com.lrc.entries.CaseInfo; import com.lrc.utils.EasyPoiExcelUtil; import io.restassured.response.Response; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import java.util.List; /** * @param * @author lrc * @create 2022/1/9 * @return * @description **/ public class Test02 extends BaseTest { @BeforeClass public void setUp(){ //向环境变量设置key Environment.envMap.put("key",Contants.KEY); } @Test(dataProvider = "readCases") public void test01(CaseInfo caseInfo){ //将测试用例做整体替换,只要遇到${}数据,就替换为环境变量中的实际数据 caseInfo=paramsReplace(caseInfo); //发起请求 Response res = request(caseInfo); //断言请求 assertResponse(res,caseInfo); //将测试用例的提取表达式保存到环境变量中 extractToEnvironment(res,caseInfo); } @DataProvider //向测试用例提供Excel数据 public Object[] readCases(){ List<CaseInfo> listDatas = EasyPoiExcelUtil.readExcel(0); return listDatas.toArray(); } }
执行结果:
成功根据我们的Excel用例输出结果。
四:数据库断言操作
在做接口测试的时候,经常需要结合数据库进行断言,提高测试用例的正确性,由于本次框架的免费API文档拿不到官方数据库信息,此处只做出介绍,不实际运行,大家可以参考到自己的实际项目当中。
1、在pom.xml中添加数据库操作包依赖:
<!-- mysql数据库驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.38</version> </dependency> <!-- 数据库连接工具包 --> <dependency> <groupId>commons-dbutils</groupId> <artifactId>commons-dbutils</artifactId> <version>1.6</version> </dependency>
2、在utils包下新建JDBCUtils工具类,编写数据库的操作
package com.lrc.utils; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.MapListHandler; import org.apache.commons.dbutils.handlers.ScalarHandler; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.List; import java.util.Map; /** * @param * @author lrc * @create 2022/1/9 * @return * @description **/ public class JDBCUtils { /** * 和数据库建立连接 * @return 数据库连接对象 */ public static Connection getConnection() { //定义数据库连接 //Oracle:jdbc:oracle:thin:@localhost:1521:DBName //SqlServer:jdbc:microsoft:sqlserver://localhost:1433; DatabaseName=DBName //MySql:jdbc:mysql://localhost:3306/DBName String url="jdbc:mysql://xxxx?useUnicode=true&characterEncoding=utf-8"; String user="xxxx"; String password="xxxx"; //定义数据库连接对象 Connection conn = null; try { conn = DriverManager.getConnection(url, user,password); } catch (SQLException throwables) { throwables.printStackTrace(); } return conn; } /** * 修改数据库数据操作(插入、修改、删除) * @param sql 要执行的sql语句 */ public static void updateData(String sql){ //1、建立连接 Connection conn = getConnection(); //2、QueryRunner对象生成 QueryRunner queryRunner = new QueryRunner(); //3、执行sql try { queryRunner.update(conn,sql); } catch (SQLException throwables) { throwables.printStackTrace(); } finally { //关闭连接 try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } } /** * 查询单个字段的数据 * @param sql 要执行的sql语句 * @return 返回查询结果 */ public static Object querySingleData(String sql){ //1、建立连接 Connection conn = getConnection(); //2、QueryRunner对象生成 QueryRunner queryRunner = new QueryRunner(); //3、执行sql Object data =null ; try { data = queryRunner.query(conn,sql,new ScalarHandler<Object>()); } catch (SQLException throwables) { throwables.printStackTrace(); } finally { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } return data; } /** * 查询所有的数据 * @param sql 要执行的sql语句 * @return 返回查询结果 */ public static List<Map<String,Object>> queryAllDatas(String sql){ //1、建立连接 Connection conn = getConnection(); //2、QueryRunner对象生成 QueryRunner queryRunner = new QueryRunner(); //3、执行sql List<Map<String,Object>> data = null; try { data = queryRunner.query(conn,sql,new MapListHandler()); } catch (SQLException throwables) { throwables.printStackTrace(); } finally { try { conn.close(); } catch (SQLException throwables) { throwables.printStackTrace(); } } return data; } }
3、在BaseTest类中添加数据库断言方法封装
/** * 数据库断言统一封装 * @param caseInfo 用例数据 */ public void assertDB(CaseInfo caseInfo){ String dbAssertInfo = caseInfo.getDbAssert(); if(dbAssertInfo != null) { Map<String, Object> mapDbAssert = JSONObject.parseObject(dbAssertInfo); Set<String> allKeys = mapDbAssert.keySet(); for (String key : allKeys) { //key为对应要执行的sql语句 Object dbActual = JDBCUtils.querySingleData(key); //根据数据库中读取实际返回类型做判断 //1、Long类型 if(dbActual instanceof Long){ Integer dbExpected = (Integer) mapDbAssert.get(key); Long expected = dbExpected.longValue(); Assert.assertEquals(dbActual, expected); }else { Object expected = mapDbAssert.get(key); Assert.assertEquals(dbActual, expected); } } } }
4、后边在需要做数据库断言的测试用例中,只需要调用该assertDB方法即可。
五:报表集成
1、在pom.xml中添加allure报表依赖:
<!--allure报表依赖--> <dependency> <groupId>io.qameta.allure</groupId> <artifactId>allure-testng</artifactId> <version>2.12.1</version> <scope>test</scope> </dependency>
2、在pom.xml的<project>标签下覆盖<properties>标签
<properties> <aspectj.version>1.8.10</aspectj.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <maven.compiler.encoding>UTF-8</maven.compiler.encoding> </properties>
3、在pom.xml的<project>标签下级中添加build标签
<build> <plugins> <plugin> <!-- maven-surefire-plugin 配合testng执行测试用例的maven插件 --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> <configuration> <!-- 测试失败后,是否忽略并继续测试 --> <testFailureIgnore>true</testFailureIgnore> <suiteXmlFiles> <!-- testng配置文件名称 --> <suiteXmlFile>testng02.xml</suiteXmlFile> </suiteXmlFiles> <!--设置参数命令行 --> <argLine> <!-- UTF-8编码 --> -Dfile.encoding=UTF-8 <!-- 配置拦截器 --> -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" </argLine> <systemProperties> <property> <!-- 配置 allure 结果存储路径 --> <name>allure.results.directory</name> <value>${project.build.directory}/allure-results</value> </property> </systemProperties> </configuration> <dependencies> <!-- aspectjweaver maven坐标 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> </dependencies> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build>
4、至此,Allure报表的集成操作已经完成了,接下来就可以使用Allure报表生成测试报告。
通过Allure报表生成报告的操作:
(1)在工程目录下新建个testng.xml文件,此处的文件需要与上述Maven Surefire插件配置的testng.xml文件名一致,填入如下信息:
<?xml version="1.0" encoding="utf-8" ?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="测试套件" > <test name="测试"> <classes> <class name="com.lemon.testcases.RegisterTest"/> <class name="com.lemon.testcases.LoginTest"/> <class name="com.lemon.testcases.GetUserInfoTest"/> <class name="com.lemon.testcases.InvestFlowTest"/> </classes> </test> </suite>
其中的class是测试用例的类名,文件放置的目录如下图:
(2)在命令行执行命令:
mvn clean test
注意:必须使用maven构建测试执行,不能直接在测试类中执行或者在testng.xml中右键执行,那样是生成不了allure报表的。
(3)生成allure报表:
mvn io.qameta.allure:allure-maven:serve
生成了allure报表:
六:日志集成
1、在之前介绍过全局配置类Contants中添加一个控制台日志开关控制权限,如果选择为false,则控制台不输出日志,将日志输出到allure报表,选择为true,则在控制台输出日志,不输出到allure报表
//控制台日志输出开关(true->输出到控制台,false->不输出到控制台) public static final boolean SHOW_CONSOLE_LOG=false;
2、在BaseTest类中的封装好的request方法添加日志输出控制逻辑:
/** * 封装所有请求类型 * @param caseInfo 测试用例对象 * @return response响应对象 */ public static Response request(CaseInfo caseInfo){ //在用例基类每个请求添加日志 String logFilepath=""; //如果开关控制为false,即不在控制台输出日志,才创建日志文件 if(!Contants.SHOW_CONSOLE_LOG) { //此处按照接口名称进行日志文件分类处理 File dirFile = new File("logs\\" + caseInfo.getInterfaceName()); if (!dirFile.exists()) { //如果文件及文件夹不存在,则创建文件及文件夹 dirFile.mkdirs(); } PrintStream fileOutPutStream = null; //日志文件路径 logFilepath = "logs\\" + caseInfo.getInterfaceName() + "\\" + caseInfo.getInterfaceName() + "_" + caseInfo.getCaseId() + ".log"; try { fileOutPutStream = new PrintStream(new File(logFilepath)); } catch (FileNotFoundException e) { e.printStackTrace(); } //每个接口请求的日志单独的保存到本地的每一个文件中 RestAssured.config = RestAssured.config().logConfig(LogConfig.logConfig().defaultStream(fileOutPutStream)); } String requestHeaders=caseInfo.getRequestHeader(); Map requestHeadersMap= JSONObject.parseObject(requestHeaders); String url=caseInfo.getUrl(); String params=caseInfo.getInputParams(); String method=caseInfo.getMethod(); Response response=null; if ("get".equalsIgnoreCase(method)) { response = RestAssured.given().log().all().headers(requestHeadersMap).when().get(url).then().log().all().extract().response(); } else if ("post".equalsIgnoreCase(method)) { response = RestAssured.given().log().all().headers(requestHeadersMap).body(params).when().post(url).then().log().all().extract().response(); } else if ("put".equalsIgnoreCase(method)) { response = RestAssured.given().log().all().headers(requestHeadersMap).body(params).when().post(url).then().log().all().extract().response(); } //可以在此处添加想要的信息到日志文件中 //请求结束之后将接口日志添加到allure报表中 if(!Contants.SHOW_CONSOLE_LOG) { try { Allure.addAttachment("接口请求响应日志", new FileInputStream(logFilepath)); } catch (FileNotFoundException e) { e.printStackTrace(); } } return response; }
3、自此,日志集成已经完成,我们在配置类Contants将SHOW_CONSOLE_LOG定义成false,将会在报表中可以查看日志:
而当我们将SHOW_CONSOLE_LOG定义成true的时候,就可以在控制台输出日志调试,不会输出到报表。
七:最后一个环节了,通过GitLab管理我们的项目代码,并提交到Jenkins持续集成部署,日后有时间会继续更新。
文章末尾附上项目源码:
链接:https://pan.baidu.com/s/126_01gLPINoGMd0mR4PGOA
提取码:jkk2
附言:文章编写不易,觉得本文写的不错的可以点点赞,关注一下,有问题的也可以留言讨论下!!!