Avatar

dubbo、http、https、jdbc
java
Linux、mac、windows
在路上 · February 01, 2018 · 7475 次阅读 · 21 条评论

背景

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

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 报警邮件接收方配置

配置文件路径:

配置文件格式:

评论列表
星云 发表于 March 29, 2018

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

baoshd 发表于 February 06, 2018

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

在路上 发表于 February 06, 2018

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

路小圣 发表于 March 06, 2018

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

在路上 发表于 March 06, 2018

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

icegreen77 发表于 March 12, 2018

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

在路上 发表于 March 12, 2018

@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 发表于 March 12, 2018

哦哦,没看仔细,哈哈

icegreen77 发表于 March 13, 2018

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

在路上 发表于 March 13, 2018

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

icegreen77 发表于 March 16, 2018

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

在路上 发表于 March 16, 2018

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

星云 发表于 March 28, 2018

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

在路上 发表于 March 28, 2018

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

viti 发表于 May 23, 2018

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

在路上 发表于 May 23, 2018

@a452164544
testngReportRecord.xml 中的 Listener

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

您好,以下的包找不到,换了 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;

love52678 发表于 January 08, 2019

同问楼上的

在路上 发表于 January 08, 2019

@gegewu_1991 你如果测试 dubbo 的话,不需要非得按照我的包导入。看看你们的 dubbo 接口需要导入什么包就行
以下都是乐视自己封装的包,你别用这些
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.letv.shop.order.status.flow.bean.OrderParam;
import com.letv.shop.order.status.flow.service.OrderStatusService;

shandongdong 发表于 May 08, 2019

你好,问下测试用例的运行怎么触发的? 每个测试用例都是一个 Excel 文件,那么这些 Excel 文件是否需要生成对应的 java 文件和 TestNG 的 xml 文件?

在路上 发表于 September 11, 2019

@shandongdong 不需要,配置好 excel 的路径,就会触发