• 接口自动化框架(java)--1.项目概述


    项目github地址:

    https://github.com/tianchiTester/API_AutoFramework

     这套框架的报告是自己封装的

    1.测试基类TestBase:

    接口请求的testcase类需要继承此类去读取properties文件

    package com.qa.base;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.util.Properties;
     
    public class TestBase {
        //这个类作为所有接口请求的父类,加载读取properties文件
        public Properties prop;
        //构造函数
        public TestBase(){
            try{
                prop = new Properties();
                FileInputStream fis = new FileInputStream(System.getProperty("user.dir")+"/src/main/java/com/qa/config/config.properties");
                prop.load(fis);
            }catch(FileNotFoundException f){
                f.printStackTrace();
            }catch (IOException i){
                i.printStackTrace();
            }
        }
    }

    2.配置文件

    配置文件里存放项目的endpoint,可以通过修改endpoint进行环境的切换

    测试数据存放读取excel的地址

    tokenpath存放jsonpath的所在路径用于需要token才能调用的接口

    #项目的根url(endpoint)
    Host= https://xxx.com
     
    #测试数据excel地址
    postdata = xxx
    getdata = xxx
     
     
    #通过jsonpath获取返回结果token的所在路径
    tokenPath = xxx

    3.Excel文件中测试数据存放接口地址endpoint后面的url

    4.report样式,我使用的是extentreprot插件,实现方式是实现testNG的IReporter接口,再通过testng.xml中listener标签进行监听

    package com.qa.report;
     
    import com.aventstack.extentreports.ExtentReports;
    import com.aventstack.extentreports.ExtentTest;
    import com.aventstack.extentreports.ResourceCDN;
    import com.aventstack.extentreports.Status;
    import com.aventstack.extentreports.model.TestAttribute;
    import com.aventstack.extentreports.reporter.ExtentHtmlReporter;
    import com.aventstack.extentreports.reporter.configuration.ChartLocation;
    import org.testng.*;
    import org.testng.xml.XmlSuite;
     
    import java.io.File;
    import java.util.*;
     
    public class ExtentTestNGReporterListener implements IReporter{
     
        //生成的路径以及文件名
        private static final String OUTPUT_FOLDER = "test-output/";
        private static final String FILE_NAME = "index.html";
        private ExtentReports extent;
     
        @Override
        public void generateReport(List<XmlSuite>  xmlSuites, List<ISuite> suites, String outputDirectory) {
            init();
            boolean createSuiteNode = false;
            if(suites.size()>1){
                createSuiteNode=true;
            }
            for (ISuite suite : suites) {
                Map<String, ISuiteResult> result = suite.getResults();
                //如果suite里面没有任何用例,直接跳过,不在报告里生成
                if(result.size()==0){
                    continue;
                }
                //统计suite下的成功、失败、跳过的总用例数
                int suiteFailSize=0;
                int suitePassSize=0;
                int suiteSkipSize=0;
                ExtentTest suiteTest=null;
                //存在多个suite的情况下,在报告中将同一个一个suite的测试结果归为一类,创建一级节点。
                if(createSuiteNode){
                    suiteTest = extent.createTest(suite.getName()).assignCategory(suite.getName());
     
                }
                boolean createSuiteResultNode = false;
                if(result.size()>1){
                    createSuiteResultNode=true;
                }
                for (ISuiteResult r : result.values()) {
                    ExtentTest resultNode;
                    ITestContext context = r.getTestContext();
                    if(createSuiteResultNode){
                        //没有创建suite的情况下,将在SuiteResult的创建为一级节点,否则创建为suite的一个子节点。
                        if( null == suiteTest){
                            resultNode = extent.createTest(r.getTestContext().getName());
                        }else{
                            resultNode = suiteTest.createNode(r.getTestContext().getName());
                        }
                    }else{
                        resultNode = suiteTest;
                    }
                    if(resultNode != null){
                        resultNode.getModel().setName(suite.getName()+" : "+r.getTestContext().getName());
                        if(resultNode.getModel().hasCategory()){
                            resultNode.assignCategory(r.getTestContext().getName());
                        }else{
                            resultNode.assignCategory(suite.getName(),r.getTestContext().getName());
                        }
                        resultNode.getModel().setStartTime(r.getTestContext().getStartDate());
                        resultNode.getModel().setEndTime(r.getTestContext().getEndDate());
                        //统计SuiteResult下的数据
                        int passSize = r.getTestContext().getPassedTests().size();
                        int failSize = r.getTestContext().getFailedTests().size();
                        int skipSize = r.getTestContext().getSkippedTests().size();
                        suitePassSize += passSize;
                        suiteFailSize += failSize;
                        suiteSkipSize += skipSize;
                        if(failSize>0){
                            resultNode.getModel().setStatus(Status.FAIL);
                        }
                        resultNode.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",passSize,failSize,skipSize));
                    }
                    buildTestNodes(resultNode,context.getFailedTests(), Status.FAIL);
                    buildTestNodes(resultNode,context.getSkippedTests(), Status.SKIP);
                    buildTestNodes(resultNode,context.getPassedTests(), Status.PASS);
                }
                if(suiteTest!= null){
                    suiteTest.getModel().setDescription(String.format("Pass: %s ; Fail: %s ; Skip: %s ;",suitePassSize,suiteFailSize,suiteSkipSize));
                    if(suiteFailSize>0){
                        suiteTest.getModel().setStatus(Status.FAIL);
                    }
                }
     
            }
     
            extent.flush();
        }
     
        private void init() {
            //文件夹不存在的话进行创建
            File reportDir= new File(OUTPUT_FOLDER);
            if(!reportDir.exists()&& !reportDir .isDirectory()){
                reportDir.mkdir();
            }
            ExtentHtmlReporter htmlReporter = new ExtentHtmlReporter(OUTPUT_FOLDER + FILE_NAME);
            htmlReporter.config().setDocumentTitle("api自动化测试报告");
            htmlReporter.config().setReportName("api自动化测试报告");
     
            htmlReporter.config().setChartVisibilityOnOpen(true);
            htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
            // htmlReporter.config().setTheme(Theme.STANDARD);
            htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
            htmlReporter.config().setCSS(".node.level-1  ul{ display:none;} .node.level-1.active ul{display:block;}");
            extent = new ExtentReports();
            extent.attachReporter(htmlReporter);
            extent.setReportUsesManualConfiguration(true);
        }
     
        private void buildTestNodes(ExtentTest extenttest,IResultMap tests, Status status) {
            //存在父节点时,获取父节点的标签
            String[] categories=new String[0];
            if(extenttest != null ){
                List<TestAttribute> categoryList = extenttest.getModel().getCategoryContext().getAll();
                categories = new String[categoryList.size()];
                for(int index=0;index<categoryList.size();index++){
                    categories[index] = categoryList.get(index).getName();
                }
            }
     
            ExtentTest test;
     
            if (tests.size() > 0) {
                //调整用例排序,按时间排序
                Set<ITestResult> treeSet = new TreeSet<ITestResult>(new Comparator<ITestResult>() {
                    @Override
                    public int compare(ITestResult o1, ITestResult o2) {
                        return o1.getStartMillis()<o2.getStartMillis()?-1:1;
                    }
                });
                treeSet.addAll(tests.getAllResults());
                for (ITestResult result : treeSet) {
                    Object[] parameters = result.getParameters();
                    String name="";
                    //如果有参数,则使用参数的toString组合代替报告中的name
    //                for(Object param:parameters){
    //                    name+=param.toString();
    //                }
                    //如果有参数只取第一个参数作test-name
                    for(int i=0;i<parameters.length;i++){
                        name = parameters[0].toString();
                    }
     
                    if(name.length()>0){
                        if(name.length()>100){
                            name= name.substring(0,100)+"...";
                        }
                    }else{
                        name = result.getMethod().getMethodName();
                    }
                    if(extenttest==null){
                        test = extent.createTest(name);
                    }else{
                        //作为子节点进行创建时,设置同父节点的标签一致,便于报告检索。
                        test = extenttest.createNode(name).assignCategory(categories);
                    }
                    //test.getModel().setDescription(description.toString());
                    //test = extent.createTest(result.getMethod().getMethodName());
                    for (String group : result.getMethod().getGroups())
                        test.assignCategory(group);
     
                    List<String> outputList = Reporter.getOutput(result);
                    for(String output:outputList){
                        //将用例的log输出报告中
                        test.debug(output);
                    }
                    if (result.getThrowable() != null) {
                        test.log(status, result.getThrowable());
                    }
                    else {
                        test.log(status, "Test " + status.toString().toLowerCase() + "ed");
                    }
     
                    test.getModel().setStartTime(getTime(result.getStartMillis()));
                    test.getModel().setEndTime(getTime(result.getEndMillis()));
                }
            }
        }
     
        private Date getTime(long millis) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(millis);
            return calendar.getTime();
        }
    }

    5.接口请求方法

    封装post方法, 普通get方法,需要header的get方法,delete方法

     1 package com.qa.restclient;
     2  
     3  
     4 import org.apache.http.client.ClientProtocolException;
     5  
     6 import org.apache.http.client.methods.CloseableHttpResponse;
     7 import org.apache.http.client.methods.HttpDelete;
     8 import org.apache.http.client.methods.HttpGet;
     9 import org.apache.http.client.methods.HttpPost;
    10 import org.apache.http.entity.StringEntity;
    11 import org.apache.http.impl.client.CloseableHttpClient;
    12 import org.apache.http.impl.client.HttpClients;
    13 import org.apache.log4j.Logger;
    14  
    15  
    16 import java.io.IOException;
    17 import java.util.HashMap;
    18 import java.util.Map;
    19  
    20  
    21 public class RestClient {
    22     //get接口带header
    23     public CloseableHttpResponse getApi(String url , Map<String,String> map) throws IOException{
    24         CloseableHttpClient httpClient = HttpClients.createDefault();
    25         HttpGet get = new HttpGet(url);
    26  
    27         for(Map.Entry<String,String> header: map.entrySet() ){
    28             get.addHeader(header.getKey(),header.getValue());
    29         }
    30         CloseableHttpResponse httpResponse = httpClient.execute(get);
    31         return httpResponse;
    32     }
    33  
    34     //普通get接口
    35     public CloseableHttpResponse getApi(String url) throws IOException{
    36         CloseableHttpClient httpClient = HttpClients.createDefault();
    37         HttpGet get = new HttpGet(url);
    38         CloseableHttpResponse httpResponse = httpClient.execute(get);
    39         System.out.println(httpResponse);
    40         return httpResponse;
    41     }
    42  
    43     //post接口
    44     public CloseableHttpResponse postApi(String url, String entityString, HashMap<String,String> headermap) throws ClientProtocolException, IOException {
    45         //创建一个可关闭的HttpClient对象
    46         CloseableHttpClient httpclient = HttpClients.createDefault();
    47         HttpPost httppost = new HttpPost(url);
    48         httppost.setEntity(new StringEntity(entityString));
    49         //加载请求头到httppost对象
    50         for(Map.Entry<String, String> entry : headermap.entrySet()) {
    51             httppost.addHeader(entry.getKey(), entry.getValue());
    52         }
    53         //发送post请求
    54         CloseableHttpResponse httpResponse = httpclient.execute(httppost);
    55         return httpResponse;
    56     }
    57  
    58  
    59     //delete方法
    60     public CloseableHttpResponse deleteApi(String url) throws ClientProtocolException, IOException {
    61         CloseableHttpClient httpclient = HttpClients.createDefault();
    62         HttpDelete httpdel = new HttpDelete(url);
    63         //发送delete请求
    64         CloseableHttpResponse httpResponse = httpclient.execute(httpdel);
    65         return httpResponse;
    66     }
    67 }

    6.测试用例

    7.工具类

    getToken:传入接口请求返回结果对象和jsonpath路径,获取token

    dtt : 读取excel中的数据,传入excel路径和excel的sheet id

    getstauteCode:获取返回结果的状态码

     1 package com.qa.util;
     2  
     3 import com.jayway.jsonpath.JsonPath;
     4 import com.jayway.jsonpath.ReadContext;
     5  
     6 import org.apache.http.client.methods.CloseableHttpResponse;
     7 import org.apache.http.util.EntityUtils;
     8 import org.apache.poi.ss.usermodel.CellType;
     9  
    10 import org.apache.poi.xssf.usermodel.XSSFCell;
    11 import org.apache.poi.xssf.usermodel.XSSFSheet;
    12 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
    13  
    14 import java.io.File;
    15 import java.io.FileInputStream;
    16 import java.io.FileNotFoundException;
    17 import java.io.IOException;
    18 import java.util.HashMap;
    19  
    20  
    21  
    22 public class TestUtil {
    23  
    24     //获取返回的token ,使用JsonPath获取json路径
    25     public static HashMap<String,String> getToken(CloseableHttpResponse closeableHttpResponse,String jsonPath) throws Exception{
    26         HashMap<String,String> responseToken = new HashMap<String, String>();
    27         String responseString = EntityUtils.toString( closeableHttpResponse.getEntity(),"UTF-8");
    28         ReadContext ctx = JsonPath.parse(responseString);
    29         String Token = ctx.read(jsonPath); //"$.EFPV3AuthenticationResult.Token"
    30         if(null == Token||"".equals(Token)){
    31             new Exception("token不存在");
    32         }
    33  
    34         responseToken.put("x-ba-token",Token);
    35         return responseToken;
    36     }
    37  
    38  
    39     //遍历excel,sheet参数
    40     public static Object[][] dtt(String filePath,int sheetId) throws IOException{
    41  
    42         File file = new File(filePath);
    43         FileInputStream fis = new FileInputStream(file);
    44  
    45         XSSFWorkbook wb = new XSSFWorkbook(fis);
    46         XSSFSheet sh = wb.getSheetAt(sheetId);
    47         int numberrow = sh.getPhysicalNumberOfRows();
    48         int numbercell = sh.getRow(0).getLastCellNum();
    49  
    50         Object[][] dttData = new Object[numberrow][numbercell];
    51         for(int i=0;i<numberrow;i++){
    52             if(null==sh.getRow(i)||"".equals(sh.getRow(i))){
    53                 continue;
    54             }
    55             for(int j=0;j<numbercell;j++) {
    56                 if(null==sh.getRow(i).getCell(j)||"".equals(sh.getRow(i).getCell(j))){
    57                     continue;
    58                 }
    59                 XSSFCell cell = sh.getRow(i).getCell(j);
    60                 cell.setCellType(CellType.STRING);
    61                 dttData[i][j] = cell.getStringCellValue();
    62             }
    63         }
    64  
    65         return dttData;
    66     }
    67  
    68     //获取状态码
    69     public static int getStatusCode(CloseableHttpResponse closeableHttpResponse){
    70         int StatusCode = closeableHttpResponse.getStatusLine().getStatusCode();
    71         return StatusCode;
    72     }
    73  
    74 }

    原文地址https://blog.csdn.net/qq_34693151/article/details/81867044

  • 相关阅读:
    Oracle 用 sqlprompt 修改 sqlplus 提示符
    Oracle cursor pin S wait on X 等待事件 说明
    Oracle 利用 rowid 提升 update 性能
    Oracle 从缓存里面查找真实的执行计划
    Linux 进程状态 说明
    Oracle 用户 对 表空间 配额(quota ) 说明
    Upon startup of Linux database get ORA27102: out of memory LinuxX86_64 Error: 28: No space left on device
    异常宕机 Ora00600 [Kccpb_sanity_check_2] 错误解决方法
    Oracle ORA04031 错误 说明
    Oracle Shared pool 详解
  • 原文地址:https://www.cnblogs.com/111testing/p/10624720.html
Copyright © 2020-2023  润新知