Java+TestNG+Excel+ExtentTestReport接口自动化测试框架

介绍一下整体我是如何做这个框架怎么怎么用的,TestNG单元测试框架,用来执行case,用例我是在Excel里面进行管理的通过poi进行读取,用ExtentTestReport来生成测试报告。
扩展:用例管理也可以用Mysql等数据库进行管理,通过Mybatis框架进行操作。

下面就看一下我只如何读取用例,执行用例,获取结果,生成测试报告吧

1.首先通过封装的Excel工具类读取case

 /**
     * @return java.lang.Object[][]
     * @Author ChengZhiHao
     * @Description //TODO 读取excel用例工具类
     * @Date 17:28 2021/6/17
     * @Param [rows, cells]行号数组,列号数组
     **/
    public static Object[][] dataS(int[] rows, int[] cells) {
        Object[][] dataS = ExcelUtil.DiscreteDataS(BUNDLE.getString("excelAddress"), BUNDLE.getString("sheet"), rows, cells);
        return dataS;
    }

其中BUNDLE.getString(“excelAddress”), BUNDLE.getString(“sheet”)是我听过读取配置文件里面我放的Excel文件地址以及文件所在sheet的名称!

2.读取到用例后通过Testng的@DataProvider这个注释来进行参数化

   /**
     * @return void
     * @Author ChengZhiHao
     * @Description //TODO admin
     * @Date 17:52 2021/6/17
     * @Param [parameter, expected]
     **/
    @Test(dataProvider = "getListGroupCase1", dataProviderClass = ReadParameter.class)
    public void getListGroupCase1(String parameter, String expected) {
        JSONObject jsonObject = HttpClientUtil.httpPostJson("testUrl", "CrmPriceGetListGroup", parameter);
        String code = jsonObject.getString("code");
        Assert.assertEquals(code, expected);
    }

3.HttpClientUtil是我封装的工具类,用来执行请求

    /**
     * @return void
     * @Author ChengZhiHao
     * @Description //TODO admin
     * @Date 17:52 2021/6/17
     * @Param [parameter, expected]
     **/
    @Test(dataProvider = "getListGroupCase1", dataProviderClass = ReadParameter.class)
    public void getListGroupCase1(String parameter, String expected) {
        JSONObject jsonObject = HttpClientUtil.httpPostJson("testUrl", "CrmPriceGetListGroup", parameter);
        String code = jsonObject.getString("code");
        Assert.assertEquals(code, expected);
    }

4.通过Testng执行case生成测试报告

<suite name="测试">
    <test name="apitechflowcontroller">

        <!--执行case-->
        <classes>
            <class name="com.qixin.cases.CrmPriceGetListGroup"></class>
        </classes>
    </test>
    <!--生成测试报告-->
    <listeners>
        <listener class-name="com.qixin.report.ExtentTestReport"/>
    </listeners>
</suite>

5.测试报告展示

在这里插入图片描述

下面是一些工具类,我创建的是maven项目。

读取Excel工具类:

  /**
     * 支持传入连续的行连续的列
     *
     * @param excelPath 文件地址
     * @param sheetName sheet名称
     * @param startRow  开始行(行号非下标索引)
     * @param endRow    结束行(行号非下标索引)
     * @param startCell 开始列(列号非下标索引)
     * @param endCell   结束列(列号非下标索引)
     * @return 读取到的excel数据
     */
    public static Object[][] continuousDataS(String excelPath, String sheetName, int startRow, int endRow, int startCell, int endCell) {
        /**准备一个二维数组存放数据*/
        Object[][] dataS = null;
        /**获取文件路径*/
        File file = new File(excelPath);
        /**获取workBook对象*/
        try {
            /**存放获取到的数据Object[row][cell]读取到的是几行几列的数据*/
            dataS = new Object[endRow - startRow + 1][endCell - startCell + 1];
            /**创建工作簿*/
            Workbook workbook = WorkbookFactory.create(file);
            /**获取sheet对象*/
            Sheet sheet = workbook.getSheet(sheetName);
            /**获取行*/
            for (int i = startRow; i <= endRow; i++) {
                Row row = sheet.getRow(i - 1);
                /**获取列*/
                for (int j = startCell; j <= endCell; j++) {
                    Cell cell = row.getCell(j - 1, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                    /**把值转换成为字符串*/
                    cell.setCellType(CellType.STRING);
                    /**获取单元格的值*/
                    String cellValue = cell.getStringCellValue();
                    dataS[i - startRow][j - startCell] = cellValue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataS;
    }
 /**
     * 支持传入非连续的行和列
     *
     * @param excelPath 文件地址
     * @param sheetName sheet名称
     * @param rows      行号数组
     * @param cells     列号数组
     * @return 读取到的excel数据
     */
    public static Object[][] DiscreteDataS(String excelPath, String sheetName, int[] rows, int[] cells) {

        /**String excelPath = "src/main/resources/TestCaseData/v1.xlsx";*/
        /**准备一个二维数组存放数据*/
        Object[][] dataS = null;
        /**获取文件路径*/

        File file = new File(excelPath);
        /**获取workBook对象*/
        //
        try {
            /**创建工作簿*/
            Workbook workbook = WorkbookFactory.create(file);
            /**获取sheet对象*/
            Sheet sheet = workbook.getSheet(sheetName);
            /**定义保存数据的数组*/
            dataS = new Object[rows.length][cells.length];
            /**获取行*/
            for (int i = 0; i < rows.length; i++) {
                /**根据行索引取出一行*/
                Row row = sheet.getRow(rows[i] - 1);
                /**获取列*/
                for (int j = 0; j < cells.length; j++) {
                    Cell cell = row.getCell(cells[j] - 1, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
                    /**把值转换成为字符串*/
                    cell.setCellType(CellType.STRING);
                    /**获取单元格的值*/
                    String cellValue = cell.getStringCellValue();
                    dataS[i][j] = cellValue;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataS;
    }

HttpClient连接池工具类

和Mybatis连接池一样的意思,具体可以自己百度一下

/**
 * @PackageName: com.czh.util
 * @ClassName: HttpClientConnection
 * @Description: HttpClientConnection/description:连接池管理器
 * @Author: ChengZhiHao
 * @Date: 2021/4/27 14:23
 * @Version: v1.0
 */
public class HttpClientConnection {

    private static PoolingHttpClientConnectionManager manager;

    static {
        SSLContextBuilder builder = new SSLContextBuilder();
        try {
            builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
            SSLConnectionSocketFactory sslSf;
            sslSf = new SSLConnectionSocketFactory(builder.build());
            // 配置同时支持 HTTP 和 HTTPS
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register(AllConstant.HTTP, PlainConnectionSocketFactory.getSocketFactory())
                    .register(AllConstant.HTTPS, sslSf).build();
            manager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            //设置最大连接数
            manager.setMaxTotal(AllConstant.MAX_TOTAL);
            //设置最大主机连接数
            manager.setDefaultMaxPerRoute(AllConstant.DEFAULT_MAX_PER_ROUTE);
        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
            e.printStackTrace();
        }
    }

    /**
     * @return org.apache.http.impl.client.CloseableHttpClient
     * @Author ChengZhiHao
     * @Description //TODO httpClient连接池
     * @Date 10:17 2021/5/7
     * @Param []
     **/
    public static CloseableHttpClient getHttpClientConnection() {
        //设置超时时间
        RequestConfig requestconfig = RequestConfig.custom()
                .setConnectTimeout(AllConstant.HTTP_CONNECT_TIME_OUT)
                .setConnectionRequestTimeout(AllConstant.HTTP_CONNECTION_REQUEST_TIME_OUT)
                .setSocketTimeout(AllConstant.HTTP_SOCKET_TIME_OUT).build();
        return HttpClients.custom()
                // 设置连接池管理
                .setConnectionManager(manager)
                .setDefaultRequestConfig(requestconfig)
                // 设置重试次数
                .setRetryHandler(new DefaultHttpRequestRetryHandler(AllConstant.RETRY_COUNT, false)).build();
    }

}

用来执行请求的HttpClientUtil工具类

我封装的方法较多,可以悬着性看一下。

/**
 * @PackageName: com.czh.util
 * @ClassName: HttpClientUtil
 * @Description: HttpClientUtil/description:http请求工具类
 * @Author: ChengZhiHao
 * @Date: 2021/4/12 14:46
 * @Version: v1.0
 */

public class HttpClientUtil {

    /**
     * 日志打印
     */
    private static final Logger log = Logger.getLogger(Test.class);
    /**
     * 加载application.properties
     */
    private static final ResourceBundle BUNDLE = ResourceBundle.getBundle("application", Locale.CHINA);

    /**
     * @return com.alibaba.fastjson.JSONObject
     * @Author ChengZhiHao
     * @Description //TODO post请求,Json格式
     * @Date 11:09 2021/5/10
     * @Param [testUrl, interfaceAddress, data]
     **/
    public static JSONObject httpPostJson(String testUrl, String interfaceAddress, String data) {
        CloseableHttpClient client = HttpClientConnection.getHttpClientConnection();
        HttpPost post = new HttpPost(BUNDLE.getString(testUrl) + BUNDLE.getString(interfaceAddress));
        log.info(BUNDLE.getString(testUrl) + BUNDLE.getString(interfaceAddress));
        post.setHeader("Content-Type", "application/json");
        JSONObject parameter = JSONObject.parseObject(data);
        post.setEntity(new StringEntity(parameter.toString(), "utf-8"));
        CloseableHttpResponse closeableHttpResponse = null;
        try {
            closeableHttpResponse = client.execute(post);
            int code = closeableHttpResponse.getStatusLine().getStatusCode();
            if (code == AllConstant.HTTP_CODE_200) {
                String result = EntityUtils.toString(closeableHttpResponse.getEntity());
                JSONObject resultJsonObject = JSONObject.parseObject(result);
                log.info(resultJsonObject);
                return resultJsonObject;
            } else {
                log.info("状态码:" + code + "," + BUNDLE.getString(testUrl) + BUNDLE.getString(interfaceAddress) + "接口请求响应错误");
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (closeableHttpResponse != null) {
                try {
                    closeableHttpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return parameter;
    }

    /**
     * @return com.alibaba.fastjson.JSONObject
     * @Author ChengZhiHao
     * @Description //TODO post请求,form-data格式
     * @Date 13:10 2021/5/10
     * @Param [testUrl, interfaceAddress, data]
     **/
    public static JSONObject httpPostFormData(String testUrl, String interfaceAddress, String data) {
        CloseableHttpClient client = HttpClientConnection.getHttpClientConnection();
        HttpPost post = new HttpPost(BUNDLE.getString(testUrl) + BUNDLE.getString(interfaceAddress));
        JSONObject parameter = JSONObject.parseObject(data);
        List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
        //通过迭代器取出所有的key,再获取每一个键对应的值
        Set<String> keySet = parameter.keySet();
        for (String key : keySet) {
            String value = (String) parameter.get(key);
            params.add(new BasicNameValuePair(key, value));
        }
        CloseableHttpResponse closeableHttpResponse = null;
        try {
            post.setEntity(new UrlEncodedFormEntity(params));
            closeableHttpResponse = client.execute(post);
            int code = closeableHttpResponse.getStatusLine().getStatusCode();
            if (code == AllConstant.HTTP_CODE_200) {
                String result = EntityUtils.toString(closeableHttpResponse.getEntity());
                log.info(closeableHttpResponse);
                JSONObject resultJsonObject = JSONObject.parseObject(result);
                log.info(resultJsonObject);
                return resultJsonObject;
            } else {
                log.info("状态码:" + code + "," + BUNDLE.getString(testUrl) + BUNDLE.getString(interfaceAddress) + "接口请求响应错误");
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (closeableHttpResponse != null) {
                try {
                    closeableHttpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return parameter;
    }

    /**
     * @return java.lang.String
     * @Author ChengZhiHao
     * @Description //TODO get请求
     * @Date 14:06 2021/5/10
     * @Param [testUrl, interfaceAddress, data]
     **/
    public static String httpGet(String testUrl, String interfaceAddress, String data) {
        CloseableHttpClient client = HttpClientConnection.getHttpClientConnection();
        CloseableHttpResponse closeableHttpResponse = null;
        try {
            URIBuilder build;
            build = new URIBuilder(BUNDLE.getString(testUrl) + BUNDLE.getString(interfaceAddress));
            JSONObject parameter = JSONObject.parseObject(data);
            if (parameter != null) {
                Set<String> keys = parameter.keySet();
                for (String key : keys) {
                    String value = (String) parameter.get(key);
                    //在请求地址上拼接参数
                    build.setParameter(key, value);
                }
            }
            HttpGet get = new HttpGet(build.build());
            closeableHttpResponse = client.execute(get);
            int code = closeableHttpResponse.getStatusLine().getStatusCode();
            if (code == AllConstant.HTTP_CODE_200) {
                String result = EntityUtils.toString(closeableHttpResponse.getEntity());
                log.info(closeableHttpResponse);
                return result;
            } else {
                log.info("状态码:" + code + "," + BUNDLE.getString(testUrl) + BUNDLE.getString(interfaceAddress) + "接口请求响应错误");
                return null;
            }
        } catch (URISyntaxException | IOException e) {
            e.printStackTrace();
        } finally {
            if (closeableHttpResponse != null) {
                try {
                    closeableHttpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return null;
    }

    /**
     * @return java.lang.String
     * @Author ChengZhiHao
     * @Description //TODO post请求,form-data格式,重定向
     * @Date 14:38 2021/5/10
     * @Param [testUrl, interfaceAddress, data]
     **/
    public static String redirectFormData(String testUrl, String interfaceAddress, String data) {
        log.info("我要测试");
        CloseableHttpClient client = HttpClientConnection.getHttpClientConnection();
        HttpPost post = new HttpPost(BUNDLE.getString(testUrl) + BUNDLE.getString(interfaceAddress));
        JSONObject parameter = JSONObject.parseObject(data);
        List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
        //通过迭代器取出所有的key,再获取每一个键对应的值
        Set<String> keySet = parameter.keySet();
        for (String key : keySet) {
            String value = (String) parameter.get(key);
            params.add(new BasicNameValuePair(key, value));
        }
        CloseableHttpResponse newCloseableHttpResponse = null;
        try {
            post.setEntity(new UrlEncodedFormEntity(params));
            CloseableHttpResponse closeableHttpResponse = client.execute(post);
            int code = closeableHttpResponse.getStatusLine().getStatusCode();
            String result = EntityUtils.toString(closeableHttpResponse.getEntity(), "UTF-8");
            log.info(result);
            if (code == AllConstant.HTTP_CODE_302) {
                //跳转的目标地址是在 HTTP-HEAD 中的
                Header header = closeableHttpResponse.getFirstHeader("location");
                System.out.println(header);
                //这就是跳转后的地址,再向这个地址发出新申请,以便得到跳转后的信息
                String newUrl = header.getValue();
                System.out.println(newUrl);
                HttpPost newPost = new HttpPost(newUrl);
                newCloseableHttpResponse = client.execute(newPost);
                String newResult = EntityUtils.toString(newCloseableHttpResponse.getEntity(), "UTF-8");
                log.info(newResult);
                return newResult;
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (newCloseableHttpResponse != null) {
                try {
                    newCloseableHttpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * @return java.lang.String
     * @Author ChengZhiHao
     * @Description //TODO post请求,Json格式,重定向
     * @Date 14:39 2021/5/10
     * @Param [testUrl, interfaceAddress, data]
     **/
    public static String redirectPost(String testUrl, String interfaceAddress, String data) {
        CloseableHttpClient client = HttpClientConnection.getHttpClientConnection();
        HttpPost post = new HttpPost(BUNDLE.getString(testUrl) + BUNDLE.getString(interfaceAddress));
        JSONObject parameter = JSONObject.parseObject(data);
        post.setEntity(new StringEntity(parameter.toString(), "utf-8"));
        CloseableHttpResponse newCloseableHttpResponse = null;
        try {
            CloseableHttpResponse closeableHttpResponse = client.execute(post);
            int code = closeableHttpResponse.getStatusLine().getStatusCode();
            String result = EntityUtils.toString(closeableHttpResponse.getEntity(), "UTF-8");
            log.info(result);
            if (code == AllConstant.HTTP_CODE_302) {
                //跳转的目标地址是在 HTTP-HEAD 中的
                Header header = closeableHttpResponse.getFirstHeader("location");
                System.out.println(header);
                //这就是跳转后的地址,再向这个地址发出新申请,以便得到跳转后的信息
                String newUrl = header.getValue();
                System.out.println(newUrl);
                HttpPost newPost = new HttpPost(newUrl);
                newCloseableHttpResponse = client.execute(newPost);
                String newResult = EntityUtils.toString(newCloseableHttpResponse.getEntity(), "UTF-8");
                log.info(newResult);
                return newResult;
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (newCloseableHttpResponse != null) {
                try {
                    newCloseableHttpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * @return com.alibaba.fastjson.JSONObject
     * @Author ChengZhiHao
     * @Description //TODO 文件上传
     * @Date 15:19 2021/5/10
     * @Param [testUrl, interfaceAddress, path]
     **/
    public JSONObject uploadFile(String testUrl, String interfaceAddress, String path) {
        File file = new File(path);
        CloseableHttpClient client = HttpClientConnection.getHttpClientConnection();
        HttpPost post = new HttpPost(BUNDLE.getString(testUrl) + BUNDLE.getString(interfaceAddress));
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.addPart("file", new FileBody(file, ContentType.DEFAULT_BINARY));
        post.setEntity(builder.build());
        CloseableHttpResponse closeableHttpResponse = null;
        try {
            //执行提交
            closeableHttpResponse = client.execute(post);
            int code = closeableHttpResponse.getStatusLine().getStatusCode();
            if (code == AllConstant.HTTP_CODE_200) {
                String result = EntityUtils.toString(closeableHttpResponse.getEntity(), StandardCharsets.UTF_8);
                JSONObject jsonObject = JSONObject.parseObject(result);
                return jsonObject;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (closeableHttpResponse != null) {
                try {
                    closeableHttpResponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}

最后希望这些能帮助大家,有什么问题可以留言,后面我会把Mysql以及Mybatis都集成进来,也会上传到githup上。

我计划写个简单的增删改查关联case,然后通过Jenkins集成执行case,把返回的结果写入数据库中,大致就这样吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值