Avatar

dubbo、http、https、jdbc
java
Linux、mac、windows
zailushang · 2018年02月01日 · 5989 次阅读 · 17 条评论

背景

因一直从事服务端测试,在人员极速减少的情况下,故开发了一套提升效率的接口自动化框架,用于提升测试效率。

github源码地址:

https://github.com/OnTheWay111/Avatar

该框架功能完善和性能优化将会一直在路上。

1、Avatar框架图

废话不多说,框架支持功能和依赖见下图:

2、已实现功能及报告展示

目前可测试dubbo、http/https、mysql
邮件报告内容如下:

附件内容如下:

3、Avatar代码结构图

废话不多说,框架代码结构及说明见下图:

4、详细功能及使用说明

4.1 dubbo接口测试

4.1.1 pom.xml中添加dubbo provider的maven库

示例:

<!-- maven仓库配置 -->
<distributionManagement>
<snapshotRepository>
<id>xxxx-snapshot</id>
<name>xxxx Snapshot</name>
<url>http://maven.xxxx.cn/nexus/</url>
</snapshotRepository>
<repository>
<id>xxxx-release</id>
<name>xxx Release</name>
<url>http://maven.xxxx.cn/content/repositories/</url>
</repository>
</distributionManagement>
<!-- 仓库地址配置,可以放置到maven工具的conf目录setting.xml进行全局配置 -->
<repositories>
<repository>
<id>xxxx-public</id>
<name>xxxx-public</name>
<releases>
</releases>
<snapshots>
</snapshots>
<url>http://maven.xxxx.cn/nexus/content/</url>
</repository>
<repository>
......
</repository>
</repositories>

4.1.2 dubbo-config.xml中配置zookeeper和dubbo接口

示例:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd"
>

<dubbo:application name="demo-consumer"/>

<!-- zookeeper地址配置 -->
<dubbo:registry address="zookeeper://10.110.112.119:2181" />

<!-- id定义为接口名,version需要和开发核实当前的接口version -->
<dubbo:reference id="IPromiseForOrderService" interface="com.order.promise.api.IPromiseForOrderService" version="1.0" check="true"/>
<dubbo:reference id="
OrderStatusService" interface="com.order.status.flow.service.OrderStatusService" version="1.2" check="true"/>
</beans>

4.1.3 导入dubbo接口参数化文件

dubbo参数化文件内容如下:

4.1.4 编写测试用例

public class TestIPromiseForOrderService {

//不需要修改:固定值变量
private static final String FILE_PATH = "/src/test/TestCaseExcelData/dubbo/"; //文件路径
public static final ApplicationContext CONTEXT = new ClassPathXmlApplicationContext("dubbo-config.xml");
private GetTestCaseExcel excelData;


//1、fileName是dubbo接口的包名, caseName是dubbo接口名
private String fileName = "com.order.promise.api"; //dubbo接口的包名作为文件名,不包含文件后缀.xls
private String caseName = "IPromiseForOrderService"; //dubbo接口名作为sheet名


//2、request随着dubbo接口的不同,需要定义指定类型
private FreeStockForOrderParam requestParam = new FreeStockForOrderParam();


//3、新建dubbo的消费者对象,需要修改类名
private IPromiseForOrderService ClassConsumer = (IPromiseForOrderService) CONTEXT.getBean(caseName);


//不需要修改: 从excel文件中读取数据,不需要修改
@DataProvider
public Object[][] Numbers() throws BiffException, IOException {
excelData = new GetTestCaseExcel(FILE_PATH, fileName, caseName);
return excelData.getExcelData();
}

//不需要修改:dubbo接口访问Provider
@Test(dataProvider = "Numbers")
public void test(HashMap<String, String> data) {

//4、从excel中取出各项参数
String orderNo = data.get("orderNo");
String operater = data.get("operater");
String channel = data.get("channel");
String operateId = data.get("operateId");
String version = PromiseVersion.V_1_0_0.getVersion();
String status = data.get("Status");
String message = data.get("Message");
String Result = data.get("Result");

//5、将请求参数导入对象requestParam中
requestParam.setOrderNo(orderNo);
requestParam.setOperater(operater);
requestParam.setChannel(channel);
requestParam.setOperateId(operateId);
requestParam.setVersion(version);

//6、定义dubbo接口请求参数,修改类名
RestRequest<FreeStockForOrderParam> request = new RestRequest<FreeStockForOrderParam>();

//不需要修改:向生产者发送请求
request.setRequest(requestParam);

//7、修改dubbo接口方法名 和 responseData类型
RestResponse responseData = ClassConsumer.freeSaleStock(request);

//8、自定义log记录内容及校验数据(根据responseData来判断dubbo接口是否请求成功)
if (responseData!=null) {
String responseStatus = responseData.getStatus().toString();
String responseMessage = responseData.getMessage().toString();
if (responseStatus.equals(status) && responseMessage.equals(message)) {
Reporter.log("期望的Status:" + status + ",期望的Message:" + message + "\n" + "实际的Status:" + responseStatus + ",实际的Message:" + responseMessage);
System.out.println("期望的Status:" + status + ",期望的Message:" + message + "\n" + "实际的Status:" + responseStatus + ",实际的Message:" + responseMessage);
Assert.assertTrue(true);

} else {
Reporter.log("期望的Status:" + status + ",期望的Message:" + message + "\n" + "实际的Status:" + responseStatus + ",实际的Message:" + responseMessage);
System.out.println("期望的Status:" + status + ",期望的Message:" + message + "\n" + "实际的Status:" + responseStatus + ",实际的Message:" + responseMessage);
Assert.assertTrue(false);

}
} else {
Reporter.log("responseData为空");
Assert.assertTrue(false);
}

}
}

4.1.5 将dubbo测试类添加到测试类列表中

配置文件路径:

配置内容:

测试结果展示:

4.2 http接口测试

4.2.1 导入http/https接口参数化文件

导入路径:

参数化文件格式:

http测试用例路径:

4.2.2 参数化文件http接口测试类编写

Java代码如下:

public class testExampleForJmeterData {
String filePath = "/src/test/TestCaseExcelData/http/"; //文件路径
String fileName = "testcase"; //文件名,不包含文件后缀.xls
String caseName = "testcase"; //sheet名
public HttpJmeterExcelData httpJmeterExcelDatademo;
public testExampleForJmeterData() throws IOException, BiffException {
httpJmeterExcelDatademo = new HttpJmeterExcelData(filePath,fileName,caseName);
}

@DataProvider
public Object[][] Numbers() throws BiffException, IOException {
return httpJmeterExcelDatademo.Numbers();
}

@Test(dataProvider = "Numbers")
public void test(HashMap<String, String> data) throws IOException, BiffException {
httpJmeterExcelDatademo.test(data);
}
}

4.2.3 自定义http/https接口Get测试类编写

代码如下:

public class testExampleForGet {
private Map<String,String> headerMap = new HashMap<String,String>(); //Map<String,String> headerMap,为header列表
private String url = ""; //String url为post请求的url
private List<String> responseDataList = new LinkedList<>(); //断言list,元素为String类型
private String httpStatus = "";
private String hostIP = "";
private String hostName = "mcart-go.lemall.com";

@Test
public void DoGetTest() throws Exception {
headerMap.put("User-Agent", "smatisance");
headerMap.put("Content-type", "application/x-www-form-urlencoded;charset:UTF-8");
headerMap.put("cookie", "ssouid=2126407; sso_tk=102XXXO0EZzx5TDSj2oFRbam2avyAm3El7RLin1zm28Aaipj2SlKPxORcufgm1O5EyBfhFbP2PDbcm4");

hostIP = new GetHostIp(hostName).getHostIP(); //从host参数化文件中读取HOST IP
// System.out.println("===================" + hostIP);

// http/https的URL
url = "https://mcart-go.com/api/query/viewCart.jsonp?provinceId=10602&cityId=10048&callback=Zepto1503543771015";

// 添加需要校验的response data
responseDataList.add("Hellosabiasnas");
responseDataList.add("lizhen");
responseDataList.add("bvghkl");

//添加需要校验的http 状态码
httpStatus = "200";

//调用http请求类进行测试
HttpGetTest httpGetTest = new HttpGetTest(headerMap, url, responseDataList, httpStatus, hostIP);

// 用例成功与否判断
try {
if(httpGetTest.isRequestSuccessful()) {
Reporter.log("ResponseStatus: " + httpGetTest.getHttpStatus());
Reporter.log("ResponseHeader: " + httpGetTest.getResponseHeader());
Reporter.log("ResponseData: " + httpGetTest.getResponseBody());

System.out.println("ResponseData: " + httpGetTest.getResponseBody());
Assert.assertTrue(true);
} else {
Reporter.log("ResponseStatus: " + httpGetTest.getHttpStatus());
Reporter.log("ResponseHeader: " + httpGetTest.getResponseHeader());
Reporter.log("ResponseData: " + httpGetTest.getResponseBody());

System.out.println("ResponseData: " + httpGetTest.getResponseBody());
Assert.assertTrue(false);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

4.2.4 自定义http/https接口Post测试类编写

代码如下:

public class testExampleForPost {
private Map<String,String> paramMap = new HashMap<String,String>(); //Map<String,String> paramMap,为post请求的参数列表
private Map<String,String> headerMap = new HashMap<String,String>(); //Map<String,String> headerMap,为header列表
private String url = ""; //String url为post请求的url
private List<String> responseDataList = new LinkedList<>(); //断言list,元素为String类型
private String httpStatus = "";
private String hostIP = "";
private String hostName = "mproduct-go.lemall.com";

@Test
public void DoPostTest() throws Exception {
//request Body
paramMap.put("params","{\"mobileHead\":{\"equipment\":{\"devHwVersion\":\"SM919\",\"channelId\":\"2003\"},\"other\"}}");

//request header
headerMap.put("cookie", "ssouid=24707; sso_tk=102XXXO0EZ2Mfdim38Aaipj2SlKPxORcufgm1O5EyBfhFbP2PDbcm4");
headerMap.put("mEncodeMethod", "none");
headerMap.put("User-Agent", "android-phone;21;zh_CN");

//从host ip参数化文件中获取hostname对应的host ip
hostIP = new GetHostIp(hostName).getHostIP();

//post请求的URL
url = "https://mproduct-go.com:443/api/query/v2/getProDetail.json?sso_tk=102XXXO0EZ2Mfdim38Aaipj2SlKPxORcufgm1O5EyBfhFbP2PDbcm4";

//需要校验的response data
responseDataList.add("message\":\"服务调用成功\"");

//需要校验的http状态码
httpStatus = "200";

//调用http post请求类
HttpPostTest httpPostTest = new HttpPostTest(paramMap, headerMap, url, responseDataList, httpStatus, hostIP);

//用例成功与否判断
try {
if(httpPostTest.isRequestSuccessful()) {
Reporter.log("ResponseStatus: " + httpPostTest.getHttpStatus());
System.out.println("ResponseStatus: " + httpPostTest.getHttpStatus());
System.out.println("ResponseHeader: " + httpPostTest.getResponseHeader());
System.out.println("ResponseData: " + httpPostTest.getResponseBody());
Assert.assertTrue(true);
} else {
Reporter.log("Status: " + httpPostTest.httpPostRequest().getStatusLine().getStatusCode());
Reporter.log("Message: " + httpPostTest.httpPostRequest().getEntity().getContent());
System.out.println("ResponseStatus: " + httpPostTest.getHttpStatus());
System.out.println("ResponseHeader: " + httpPostTest.getResponseHeader());
System.out.println("ResponseData: " + httpPostTest.getResponseBody());
Assert.assertTrue(false);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

4.3 mysql测试

mysql测试用例类路径:

4.3.1 mysql测试用例类编写

代码如下:

public class SqlTest {
//jdbc路径
private String DBurl = "jdbc:mysql://127.0.0.1/test";
//jdbc驱动
private String JdbcName = "com.mysql.jdbc.Driver";
//mysql用户名
private String UserName = "root";
//密码
private String PassWord = "root";

private SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
String strDate = df.format(new Date());

//要执行的sql语句,支持增删改查
private String sql = "INSERT INTO runoob_tbl1 (runoob_title, runoob_author, submission_date) VALUES (\"Memcached\", \"Memcached.com\", '" + strDate + "')";

//sql请求、执行,并判断用例成功与否
@Test
public void SqlTest() {
DBHelper dbHelper = new DBHelper(DBurl, JdbcName, UserName, PassWord, sql);

if(dbHelper.isRequestSuccessful()) {
Reporter.log("sql执行成功");
Assert.assertTrue(true);
} else {
Reporter.log("sql执行失败");
Assert.assertTrue(false);
}
}
}

4.4 HOST IP设置

4.4.1 host文件导入

host文件导入路径:

host文件格式:

4.4.2 待测试环境配置

配置文件路径:

配置方式:

4.5 报警邮件配置

4.5.1 报警邮件发送方配置

配置文件路径:

配置文件内容:

4.5.2 报警邮件接收方配置

配置文件路径:

配置文件格式:

评论列表
星云 发表于 2018年03月29日

@zailushang 谢谢!学习下大佬的工程~

baoshd 发表于 2018年02月06日

private FreeStockForOrderParam requestParam = new FreeStockForOrderParam();
FreeStockForOrderParam 怎么处理,我一直报错。java初学者

zailushang 发表于 2018年02月06日

FreeStockForOrderParam这是公司内部类,你要换成你们自己的类

陆六 发表于 2018年03月06日

小白询问下,接口如果有连续加密解密如何写入Excel中?返回json如何解析判断写入Excel中?

zailushang 发表于 2018年03月06日

这个功能还没增加,目前需要自己写代码实现了

icegreen77 发表于 2018年03月12日

楼主我看了你的代码,你的接口校验有问题吧,你只是断言了服务调用是不是成功,没有校验响应参数正不正确

zailushang 发表于 2018年03月12日

@icegreen77
校验了,response body内容校验如下:
public void DoGetTest() throws Exception {
headerMap.put("User-Agent", "smatisance");
headerMap.put("Content-type", "application/x-www-form-urlencoded;charset:UTF-8");
headerMap.put("cookie", "ssouid=2126494707; sso_tk=102XXXO0EZzx5TDSj2oFRbam2avyAm3El7RLin1zm2tvubfEFUy1cJfHZElJVW3Um30ffBYl7GvOkm2Mfdim38Aaipj2SlKPxORcufgm1O5EyBfhFbP2PDbcm4");

hostIP = new GetHostIp(hostName).getHostIP(); //从host参数化文件中读取HOST IP
// System.out.println("===================" + hostIP);

url = "https://mcart-go.lemall.com/api/query/viewCart.jsonp?provinceId=10002&cityId=" + "10048" + "&arrivalId=10501&toPay=0&deviceid=&version=4.0&rs=1100&_=1503543771058&callback=Zepto1503543771015";

//需要校验的response body内容如下:
responseDataList.add("Hellosabiasnas");
responseDataList.add("lizhen");
responseDataList.add("bvghkl");
httpStatus = "200";

HttpGetTest httpGetTest = new HttpGetTest(headerMap, url, responseDataList, httpStatus, hostIP);

}

icegreen77 发表于 2018年03月12日

哦哦,没看仔细,哈哈

icegreen77 发表于 2018年03月13日

突然想到个问题,如果你的excel仅仅作为请求参数的维护的话是不是放yaml或者xml更容易操作?

zailushang 发表于 2018年03月13日

@icegreen77
是的,这个是格式问题,其实都可以。
yaml和xml进行用例复杂参数设计,但是单接口多用例管理上,可能还是excel比较方便吧。

icegreen77 发表于 2018年03月16日

再请教个问题哈,你的reportng目录下放的是源码吗?哪部分是你修改的?

zailushang 发表于 2018年03月16日

@icegreen77 主要修改了html报告的内容org.reportng.HTMLReporter

星云 发表于 2018年03月28日

这个要先编译dubbo么?我这有些依赖好像出错了:“Failed to read artifact descriptor for com.alibaba:dubbo:jar:2.8.4.2”

zailushang 发表于 2018年03月28日

@xingopq 这是因为pom文件中 加载的资源是dubbo:jar:2.8.4.2,这是我们公司内部开发的版本,你可以修改成官方版本,资源地址:http://mvnrepository.com/artifact/com.alibaba/dubbo/2.6.1

viti 发表于 2018年05月23日

测试报告怎么生成啊,代码里好像没看到调用

zailushang 发表于 2018年05月23日

@a452164544
testngReportRecord.xml中的Listener

<suite name="online下单全流程线上监控">
<listeners>
<listener class-name="org.reportng.HTMLReporter" />
</listeners>
<tests>
gegewu_1991 发表于 2018年06月03日

您好,以下的包找不到,换了 dubbo 官方的架包也不行啊
import com.alibaba.dubbo.common.serialize.support.kryo.RestRequest;
import com.alibaba.dubbo.common.serialize.support.kryo.RestResponse;
import com.lemall.srd.order.promise.api.IPromiseForOrderService;
import com.lemall.srd.order.promise.domain.common.PromiseVersion;
import com.lemall.srd.order.promise.domain.request.FreeStockForOrderParam;
import com.alibaba.dubbo.common.serialize.support.kryo.RestRequest;
import com.alibaba.dubbo.common.serialize.support.kryo.RestResponse;
import com.letv.shop.order.status.flow.bean.OrderParam;
import com.letv.shop.order.status.flow.service.OrderStatusService;