精华内容
下载资源
问答
  • 文件:E:\最全面的Java接口自动化测试实战\project.zip E:\最全面的Java接口自动化测试实战\第10章 项目实战接口开发SpringBoot E:\最全面的Java接口自动化测试实战\第11章 数据持久层框架MyBatis的应用 E:\最全面的...
  • 主要介绍了java接口自动化测试框架及断言详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Java接口自动化测试

    2019-01-21 22:47:35
    Java+接口自动化测试视频教程,视频高清,讲解易懂,楼主也一直在学习,
  • 主要介绍了Java接口自动化测试框架设计 Get请求方法和测试,框架设计我们只是介绍基本的组件,而且框架设计没有想象那么难,一步一步跟着做就会了。这篇我们来演示,如果通过Java代码来实现一个用纯代码实现Http中的...
  • 主要对举例对国家气象局接口自动化测试进行讲解(Get请求及结果断言),以达到自动化测试入门目的,需要有一定的JAVA知识(HTTP相关)。
  • 接口测试框架 https://blog.csdn.net/qq_15283475/article/details/106494544 com.bjci.api #包名 ApiInfoModel.java ## Api类 ExcelUtills.java ##操作excel的类 HandlsUtils.java ##根据judge分发不同的...
  • Java接口测试自动化

    2019-04-18 12:03:29
    java接口自动化测试视频教程testng httpclient mock jenkins集成
  • JAVA接口自动化实战

    2019-08-09 18:18:18
    JAVA接口自动化实战 网盘链接
  • 接口自动化测试框架

    2018-04-02 22:38:53
    搭建接口自动化测试框架 搭建接口自动化测试框架 搭建接口自动化测试框架 搭建接口自动化测试框架
  • 基于Springboot+Mybatis打造接口自动化测试框架-全网最新最全最具技术含量的接口自动化测试及框架编写
  • 个人觉得这个工具比任何自动化测试框架都好使,使用关键字和数据双驱动,不需要写一行代码,无需维护脚本,只需要维护用例数据。Web元素只需要在Chrome中复制xPath即可,定位非常高效。 工具安全无木马,目的只为...
  • 接口自动化测试.pdf

    2020-08-04 17:30:18
    python+ddt+unittest数据驱动,接口自动化测试框架介绍,用于团队内部培训和技术分享。
  • Java接口自动化测试框架

    千次阅读 2019-11-21 12:07:20
    自动化测试框架 1. 测试框架TestNG 1.1 适合测试人员使用的原因 (1)比Junit涵盖功能更全面的测试框架 (2)Junit更适合隔离性比较强的单元测试 (3)TestNG更适合复杂的集成测试 1.2 基本介绍 (1)基本注解:...

    一. 自动化测试框架

    在这里插入图片描述

    1. 测试框架TestNG

    1.1 适合测试人员使用的原因

    (1)比Junit涵盖功能更全面的测试框架
    (2)Junit更适合隔离性比较强的单元测试
    (3)TestNG更适合复杂的集成测试

    1.2 基本介绍

    (1)基本注解:决定执行顺序
    例:
    @Test:标记一个类或方法作为测试的一部分
    @beforeTest、@afterTest:做前置或后置处理
    (2)属性
    例:
    groups:分组测试
    dependsOnGroups:依赖测试
    description:描述
    (3)测试套件
    组织测试类一起执行的或者一组行为的测试用例的集合,由一个XML文件标记

    2. 测试报告ExtentReport

    2.1 添加测试类

    ExtentTestNGIReporterListener

    2.2 基本配置

    在测试套件中 @listener标签下添加监听器

    3. HttpClient

    一个HTTP客户端编程工具,可用来发送请求、接收响应

    4. MyBatis

    持久层框架,支持定制化 SQL、存储过程以及高级映射。
    可以使用简单的 XML 或注解来配置和映射原生信息。

    5. MySQL

    存储测试用例

    二. 编写步骤及文件目录结构

    1. 测试用例的表结构设计

    在这里插入图片描述

    2. 基础配置文件设计

    在这里插入图片描述

    2.1 pom.xml:引入第三方依赖包

    配置httpclient、json、mybatis、mysql、lombok、extentreports、testng的各种依赖

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>AutoTest</artifactId>
            <groupId>Chapter</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>Chapter12</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.1.2</version>
            </dependency>
            <dependency>
                <groupId>org.json</groupId>
                <artifactId>json</artifactId>
                <version>20170516</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.4.4</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.14</version>
            </dependency>
            <dependency>
                <groupId>com.relevantcodes</groupId>
                <artifactId>extentreports</artifactId>
                <version>2.41.1</version>
            </dependency>
            <dependency>
                <groupId>com.vimalselvam</groupId>
                <artifactId>testng-extentsreport</artifactId>
                <version>1.3.1</version>
            </dependency>
            <dependency>
                <groupId>com.aventstack</groupId>
                <artifactId>extentreports</artifactId>
                <version>3.0.6</version>
            </dependency>
            <dependency>
                <groupId>org.testng</groupId>
                <artifactId>testng</artifactId>
                <version>6.10</version>
            </dependency>
            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.0.4</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
        </dependencies>
    </project>
    

    2.2 databaseConfig.xml:数据库配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    
    <configuration>
        <!-- 注册对象的空间命名 -->
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <!-- 1.加载数据库驱动 -->
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <!-- 2.数据库连接地址 -->
                    <property name="url" value="jdbc:mysql://localhost:3306/course?serverTimezone=GMT"/>
                    <!-- 数据库用户... -->
                    <property name="username" value="root"/>
                    <!-- 数据库密码... -->
                    <property name="password" value="12345678"/>
                </dataSource>
            </environment>
        </environments>
        <!-- 注册映射文件:java对象与数据库之间的xml文件路径! -->
        <mappers>
            <mapper resource="mapper/SQLMapper.xml"/>
        </mappers>
    </configuration>
    

    2.3 application.properties:接口信息配置文件

    test.url=http://localhost:8080
    
    #登陆接口uri
    login.uri=/v1/login
    

    2.4 testng.xml:用以执行所有testng的测试套件

    <?xml version="1.0" encoding="UTF-8" ?>
    <suite  name="用户管理系统测试套件">
        <test name="用户管理系统测试用例">
            <classes>
                <class name="com.tester.cases.LoginTest">
                    <methods>
                        <include name="loginTrue"/>
                        <include name="loginFalse"/>
                    </methods>
                </class>       
            </classes>
        </test>
        <listeners>
            <listener class-name="com.tester.config.ExtentTestNGIReporterListener"/>
        </listeners>
    </suite>
    

    2.5 SQLMapper.xml:用以存储所有测试用例的SQL语句

    <?xml version="1.0" encoding="UTF-8" ?>
    
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.tester.model">
        <!--获取登陆接口case-->
        <select id="loginCase" parameterType="Integer" resultType="com.tester.model.LoginCase">
            select *from logincase where id=#{id};
        </select>
     </mapper>
    

    3. model层、config层、utils层、cases层

    在这里插入图片描述

    3.1 model层:放置各个接口的数据配置文件+InterfaceName枚举

    3.1.1 放置登录接口的数据配置文件LoginCase.java

    package com.tester.model;
    
    import lombok.Data;
    
    @Data
    public class LoginCase {
        private int id;
        private String userName;
        private String password;
        private String expected;
    }
    

    3.1.2 InterfaceName.java

    package com.tester.model;
    
    public enum InterfaceName {
        LOGIN
    }
    

    3.2 Config层:配置信息TestConfig类+ExtentTestNGReportListener类

    3.2.1TestConfig类:声明各个测试用例的URL、和之后要用的一些全局变量

    package com.tester.config;
    
    import lombok.Data;
    import org.apache.http.client.CookieStore;
    import org.apache.http.impl.client.DefaultHttpClient;
    
    
    
    @Data
    public class TestConfig {
        //登陆接口uri
        public static String loginUrl;
        //声明http客户端
        public static DefaultHttpClient defaultHttpClient;
        //用来存储cookies信息的变量
        public static CookieStore store;
    }
    

    3.2.2 ExtentTestNGReportListener类:测试报告配置

    package com.tester.config;
    
    
    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 com.aventstack.extentreports.reporter.configuration.Theme;
    import org.testng.*;
    import org.testng.xml.XmlSuite;
    
    import java.io.File;
    import java.util.*;
    
    public class ExtentTestNGIReporterListener 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);
                    }
                }
    
            }
    //        for (String s : Reporter.getOutput()) {
    //            extent.setTestRunnerOutput(s);
    //        }
    
            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);
            // 设置静态文件的DNS
            //怎么样解决cdn.rawgit.com访问不了的情况
            htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
    
            htmlReporter.config().setDocumentTitle("api自动化测试报告");
            htmlReporter.config().setReportName("api自动化测试报告");
            htmlReporter.config().setChartVisibilityOnOpen(true);
            htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
            htmlReporter.config().setTheme(Theme.STANDARD);
            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();
                    }
                    if(name.length()>0){
                        if(name.length()>50){
                            name= name.substring(0,49)+"...";
                        }
                    }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();
        }
    }
    

    3.3 utils层: 抽取公用的方法ConfigFile类+DatabaseUtil类

    3.3.1 ConfigFile类:对各个测试用例的URL进行赋值

    package com.tester.utils;
    
    import com.tester.model.InterfaceName;
    
    import java.util.Locale;
    import java.util.ResourceBundle;
    
    public class ConfigFile {
        public static ResourceBundle bundle=ResourceBundle.getBundle("application", Locale.CHINA);
        public static String getUrl(InterfaceName name){
            String address=bundle.getString("test.url");
            String uri="";
            String testUrl;
         
            if(name==InterfaceName.LOGIN){
                uri=bundle.getString("login.uri");
            }
            
            testUrl=address+uri;
            return testUrl;
        }
    }
    

    3.3.2 DatabaseUtil类:配置一个getSqlSession()方法

    作用是执行配置文件SQLMapper中的SQL语句

    package com.tester.utils;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.Reader;
    
    public class DatabaseUtil {
        public static SqlSession getSqlSession() throws IOException {
            //获取配置的资源文件
            Reader reader= Resources.getResourceAsReader("databaseConfig.xml");
            //得到SqlSessionFactory,使用类加载器加载xml文件
            SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(reader);
            //得到sqlsession对象,这个对象就能执行配置文件中的sql语句啦
            SqlSession session=factory.openSession();
            return session;
        }
    }
    

    3.4 cases层:用来放接口的测试用例

    package com.tester.cases;
    
    import com.tester.config.TestConfig;
    import com.tester.model.InterfaceName;
    import com.tester.model.LoginCase;
    import com.tester.utils.ConfigFile;
    import com.tester.utils.DatabaseUtil;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.util.EntityUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.json.JSONObject;
    import org.testng.Assert;
    import org.testng.annotations.BeforeTest;
    import org.testng.annotations.Test;
    
    import java.io.IOException;
    
    public class LoginTest {
        @BeforeTest(groups = "loginTrue",description = "测试准备工作,获取HttpClient对象")
        public void beforeTest(){
            TestConfig.getUserInfoUrl= ConfigFile.getUrl(InterfaceName.GETUSERINFO);
            TestConfig.getUserListUrl=ConfigFile.getUrl(InterfaceName.GETUSERLIST);
            TestConfig.addUserUrl=ConfigFile.getUrl(InterfaceName.ADDUSERINFO);
            TestConfig.loginUrl=ConfigFile.getUrl(InterfaceName.LOGIN);
            TestConfig.updateUserInfoUrl=ConfigFile.getUrl(InterfaceName.UPDATEUSERINFO);
    
            TestConfig.defaultHttpClient=new DefaultHttpClient();
        }
    
        @Test(groups = "loginTrue",description = "用户成功登陆接口")
        public void loginTrue() throws IOException {
            SqlSession session= DatabaseUtil.getSqlSession();
            LoginCase loginCase=session.selectOne("loginCase",1);
            System.out.println(loginCase.toString());
            System.out.println(TestConfig.loginUrl);
    
            //下边的代码为写完接口的测试代码
            String result=getResult(loginCase);
            //处理结果,就是判断返回结果是否符合预期
            Assert.assertEquals(loginCase.getExpected(),result);
        }
    
    
    
        @Test(groups = "loginFalse",description = "用户登录接口失败")
        public void loginFalse() throws IOException {
            SqlSession session=DatabaseUtil.getSqlSession();
            LoginCase loginCase=session.selectOne("loginCase",2);
            System.out.println(loginCase.toString());
            System.out.println(TestConfig.loginUrl);
    
            //下边的代码为写完接口的测试代码
            String result=getResult(loginCase);
            //处理结果,就是判断返回结果是否符合预期
            Assert.assertEquals(loginCase.getExpected(),result);
        }
    
        private String getResult(LoginCase loginCase) throws IOException {
            //下边的代码为写完接口的测试代码
            HttpPost post=new HttpPost(TestConfig.loginUrl);
            JSONObject param=new JSONObject();
            param.put("userName",loginCase.getUserName());
            param.put("password",loginCase.getPassword());
            //设置请求头信息,设置header
            post.setHeader("content-type","application/json");
            //将参数信息添加到方法中
            StringEntity entity=new StringEntity(param.toString(),"utf-8");
            post.setEntity(entity);
            //声明一个对象来进行响应结果的存储
            String result;
            //执行post方法
            HttpResponse response=TestConfig.defaultHttpClient.execute(post);
            //获取响应结果
            result= EntityUtils.toString(response.getEntity(),"utf-8");
            System.out.println(result);
    
            TestConfig.store=TestConfig.defaultHttpClient.getCookieStore();
            return result;
        }
    }
    
    展开全文
  • 所以,对于即将开始的http接口测试需求,立马花了两天时间搭建了一个http接口自动化测试框架用于测试后期回归测试,实在是被大量的重复手工执行搞怕了。最方便的方法就是用python直接写代码,代码和测试数据分离,...
  • 接口自动化测试依赖jar包,commons-io-2.4;httpclient-4.5.5;httpclient-cache-4.5.5;httpclient-win-4.5.5;httpcore-4.4.9;httpmime-4.5.5
  • 最全面的Java接口自动化测试实战.zip
  • Jmeter接口自动化测试框架是我自己写的文档,很适合想入门接口自动化的人,该文档很详细,没有一点跳步,值得想入门的人看
  • java接口自动化.txt

    2020-02-18 18:38:24
    第01章 接口自动化测试整体认知 第02章 接口测试的用例设计 第03章 手工接口测试到自动化框架设计 第04章 企业级代码管理工具git的应用 第05章 测试框架TestNG 第06章 测试报告 第07章 Mock接口框架的应用实战...
  • 这个接口自动化测试框架到目前为止,我们已经完成了Get请求的封装和必要的工具类的支持。...所以,这个Java接口自动化测试框架的核心就是Get和POST请求方法的封装过程。 1.POST接口举例浏览器打开https://re...

           这个接口自动化测试框架到目前为止,我们已经完成了Get请求的封装和必要的工具类的支持。接下来这篇,我来介绍如何完成POST请求的封装过程。一般来说,在一个项目中,接口测试很多时候就是测试Get和POST方法,其他的请求方式的接口很少,占的比重几乎不计。所以,这个Java接口自动化测试框架的核心就是Get和POST请求方法的封装过程。

     

    1.POST接口举例

    浏览器打开https://reqres.in/,下拉一屏。点击第一个POST请求,这个接口的介绍信息如下。

          这个接口的作用是创建用户,参数是一个json类型的数据,一个name一个job,两个JSON对象。发送请求之后,返回的JSON数据有name和job和id,以及创建时间这几个数据。

     

    2.Postman手动实现

     

    我们先在本地postman环境,先来手动测试实现下这个post接口的请求过程。

    这个post接口请求还是比较简单,很容易在postman上实现该请求。

     

    3.Java代码自动化实现

     

           我们已经可以正确地在postman上实现创建用户这个接口的手动测试,那么我们想要这个过程自动化实现,如何做呢。下面我在RestClient.java封装了两个方法,一个是带请求头信息的Get请求,一个是带请求头信息的POST请求方法。这篇,了解了POST请求方法,带请求头的Get方法封装就很好理解。

    package com.qa.restclient;
    
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    
    public class RestClient {
        
        
        //1. Get 请求方法
        public CloseableHttpResponse get(String url) throws ClientProtocolException, IOException {
            
            //创建一个可关闭的HttpClient对象
            CloseableHttpClient httpclient = HttpClients.createDefault();
            //创建一个HttpGet的请求对象
            HttpGet httpget = new HttpGet(url);
            //执行请求,相当于postman上点击发送按钮,然后赋值给HttpResponse对象接收
            CloseableHttpResponse httpResponse = httpclient.execute(httpget);
            
            return httpResponse;
        }
        
        //2. Get 请求方法(带请求头信息)
        public CloseableHttpResponse get(String url,HashMap<String,String> headermap) throws ClientProtocolException, IOException {
                
            //创建一个可关闭的HttpClient对象
            CloseableHttpClient httpclient = HttpClients.createDefault();
            //创建一个HttpGet的请求对象
            HttpGet httpget = new HttpGet(url);
            //加载请求头到httpget对象
            for(Map.Entry<String, String> entry : headermap.entrySet()) {
                httpget.addHeader(entry.getKey(), entry.getValue());
            }
            //执行请求,相当于postman上点击发送按钮,然后赋值给HttpResponse对象接收
            CloseableHttpResponse httpResponse = httpclient.execute(httpget);
                
            return httpResponse;
        }
        
        //3. POST方法
        public CloseableHttpResponse post(String url, String entityString, HashMap<String,String> headermap) throws ClientProtocolException, IOException {
            //创建一个可关闭的HttpClient对象
            CloseableHttpClient httpclient = HttpClients.createDefault();
            //创建一个HttpPost的请求对象
            HttpPost httppost = new HttpPost(url);
            //设置payload
            httppost.setEntity(new StringEntity(entityString));
            
            //加载请求头到httppost对象
            for(Map.Entry<String, String> entry : headermap.entrySet()) {
                httppost.addHeader(entry.getKey(), entry.getValue());
            }
            //发送post请求
            CloseableHttpResponse httpResponse = httpclient.execute(httppost);
            return httpResponse;
        }
        
        
    }
    
    
    

          然后,我们需要写一个TestNG测试用例来测试下这个封装的post方法好不好用。由于我们去前面几篇文章介绍了TestNG测试get方法的代码,这里我们就直接拷贝和修改部分代码就行。

          在写测试用例之前,我们需要提前准备好json数据,一般来说,在Java中JSON数据都是放在JAVA Bean类中,通过JSON把高级对象序列化成JSON对象。

          在src/main/java中新建包:com.qa.data,然后新建一个Users.java,这个命名就参考接口的url单词就行。在postman或者网站该post方法,我们知道,需要name和job这两个json对象。我们新建一个bean类,同alt+shift+s,然后选择生成构造方法和set和get方法。

    package com.qa.data;
    
    public class Users {
    
    	private String name;
    	private String job;
    	
    	public Users() {
    		super();
    	}
    
    	public Users(String name, String job) {
    		super();
    		this.name = name;
    		this.job = job;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getJob() {
    		return job;
    	}
    
    	public void setJob(String job) {
    		this.job = job;
    	}
    	
    }
    

         好了,在src/test/java下的com.qa.tests我们新建一个POST测试用例,现在我们的TestNG测试类代码如下:

    package com.qa.tests;
    
    import java.io.IOException;
    import java.util.HashMap;
    
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.util.EntityUtils;
    import org.testng.Assert;
    import org.testng.annotations.BeforeClass;
    import org.testng.annotations.Test;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.qa.base.TestBase;
    import com.qa.data.Users;
    import com.qa.restclient.RestClient;
    import com.qa.util.TestUtil;
    
    public class PostApiTest extends TestBase {
    	TestBase testBase;
    	String host;
    	String url;
    	RestClient restClient;
    	CloseableHttpResponse closeableHttpResponse;
    	
    	
    	@BeforeClass
    	public void setUp() {
    		testBase = new TestBase();
    		host = prop.getProperty("HOST");
    		url = host + "/api/users";
    		
    	}
    	
    	@Test
    	public void postApiTest() throws ClientProtocolException, IOException {
    		restClient = new RestClient();
    		//准备请求头信息
    		HashMap<String,String> headermap = new HashMap<String,String>();
    		headermap.put("Content-Type", "application/json"); //这个在postman中可以查询到
    		
    		//对象转换成Json字符串
    		Users user = new Users("Anthony","tester");
    		String userJsonString = JSON.toJSONString(user);
    		//System.out.println(userJsonString);
    		
    		closeableHttpResponse = restClient.post(url, userJsonString, headermap);
    		
    		//验证状态码是不是200
    		int statusCode = closeableHttpResponse.getStatusLine().getStatusCode();
    		Assert.assertEquals(statusCode, RESPNSE_STATUS_CODE_201,"status code is not 201");
    		
    		//断言响应json内容中name和job是不是期待结果
    		String responseString = EntityUtils.toString(closeableHttpResponse.getEntity());
    		JSONObject responseJson = JSON.parseObject(responseString);
    		//System.out.println(responseString);
    		String name = TestUtil.getValueByJPath(responseJson, "name");
    		String job = TestUtil.getValueByJPath(responseJson, "job");
    		Assert.assertEquals(name, "Anthony","name is not same");
    		Assert.assertEquals(job, "tester","job is not same");
    		
    	}
    
    }
    

          建议,在写测试用例过程中,需要和postman上的请求结果参考,特别是Headers这里的键值对。这里留一个作业,上面我写了一个Get带请求头的封装方法,你可以对照postman中的请求头去写一个单元测试用例去测试下这个带headers的Get方法。

           目前,Java接口自动化测试框架的核心部分,http请求方法的封装已经完成。接下里还有测试日志,测试报告,或者其他需要抽取优化的模块去完成。




    展开全文
  • java接口自动化测试源码 , 技术问题qq群:524212543 , 版本更新 v2.3 2018/01/28 增加发送邮件服务器配置项,修复终端乱码 v2.2 2018/01/20 更新说明文件和democase v2.1 2018/01/09 更新最新chromewebdriver解决...
  • Java接口自动化测试框架设计-1-开发环境的搭建

    万次阅读 多人点赞 2018-05-21 23:58:05
    废话不多说,刚开始,尽量详细,通过一步一步,手把手教会你搭建接口自动化测试的基础项目环境。 一.前提条件 我这里来一个约定,有以下前提条件。1.本机环境安装了maven并配置环境变量2.本机环境安装了Eclipse...

          本篇作为这个系列第一篇,主要介绍基础环境搭建过程。废话不多说,刚开始,尽量详细,通过一步一步,手把手教会你搭建接口自动化测试的基础项目环境。

     

    一.前提条件

     

    我这里来一个约定,有以下前提条件。

    1.本机环境安装了maven并配置环境变量

    2.本机环境安装了Eclipse软件

    3.本机环境安装了Java jdk 8版本

    4.本机需要能连接上互联网

     

           我这里还是选择了Eclipse,当然如果你有IntellijIDEA,当然也可以,我以下截图都是以Eclipse软件界面为准。如果没有接触过maven,不知道如何安装环境,请参考我这篇文章:https://blog.csdn.net/u011541946/article/details/78085989

     

    二.Eclipse上创建一个Maven工程

     

    在Eclipse中,点击File-new-project,选择Maven Project,如下图。


    点击多次Next按钮,直到出现下面界面。

     

           参考上面红圈位置,填写Group Id和Artifact Id,其中Artifact Id在Eclipse中反映出来就是项目名称,点击Finish按钮,Eclipse中新建的项目结构如下图。

     

           把main和test下包和相关class文件(自动生成的)删除,因为我们接下来不使用Junit,而是使用TestNG, 如果删除,后面我们编辑pom.xml的时候会报错。找到下面图红圈,删除这两个包。


    删除之后,test和main下都是空的文件结构。


    接下来,我们就编辑pom.xml,并添加一些我们需要的第三方插件lib的依赖和引用。

     

    三.添加必要的组件依赖

     

    在maven项目下,找到pom.xml文件,右键,打开方式选择记事本。


           我们先把junit的maven依赖给删除,然后这里,我们举例添加httpclient,因为我们需要做基于Java语言的接口自动化测试,httpclient和httpcore这两个是主要的组件。通过学习如何添加httpclient过程,其他的lib包就参考就能学会。

     

    1)打开浏览器,打开百度,搜索httpclient maven


    上面两个链接都可以,这里我选择第二个链接打开。

    2)点击第二个链接


    把上面红圈的文本内容复制到Eclipse项目中的pom.xml文件,添加之后如下效果。


    3)在Eclipse上的pom.xml,按下ctrl+s,保存之后,会发现依赖包自动下载到本地


    只要在pom.xml文件中输入正确的组件依赖文本内容,保存之后自动下载相关依赖包到本地(红圈位置)

    4)依次添加其他组件

    从上面httpclient组件添加过程,我们学会了一个基于mava依赖的组件添加到本地工程的过程,下面我们需要添加httpcore, testing, fastjson


         Httpcore主要是网络相关的组件,我们使用Http请求就需要网络相关底层方法。Testng主要是取代junit,是一个单元测试框架,方便我们编写接口自动化用例。Fastjson是阿里巴巴的一个json的开源的组件,据说是最快的json的组件,主要用来json序列化和反序列操作。

         到这里,我们就把基础的开发环境给搭建好了,接下来我们写一个Get请求的过程。

     

    展开全文
  • java接口自动化接口测试

    千次阅读 2019-08-27 10:24:09
    这里测试接口为spring boot开发接口文章中开发好的接口测试用例

    在这里插入图片描述


    功能介绍

    实现接口自动化测试代码。
    注:这里测试的接口是spring boot开发接口中开发好的接口,只需运行application.java中的main方法,即可启动接口。



    使用框架

    • httpclient
    • mybatis
    • testng



    pom文件

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.course</groupId>
        <artifactId>requestTest</artifactId>
        <version>1.0-SNAPSHOT</version>
    
    
        <properties>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.1.2</version>
            </dependency>
            <dependency>
                <groupId>org.json</groupId>
                <artifactId>json</artifactId>
                <version>20170516</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.4.5</version>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.17</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.16.14</version>
            </dependency>
            <dependency>
                <groupId>com.relevantcodes</groupId>
                <artifactId>extentreports</artifactId>
                <version>2.41.1</version>
            </dependency>
            <dependency>
                <groupId>com.vimalselvam</groupId>
                <artifactId>testng-extentsreport</artifactId>
                <version>1.3.1</version>
            </dependency>
            <dependency>
                <groupId>com.aventstack</groupId>
                <artifactId>extentreports</artifactId>
                <version>3.0.6</version>
            </dependency>
            <dependency>
                <groupId>org.testng</groupId>
                <artifactId>testng</artifactId>
                <version>6.10</version>
            </dependency>
            <dependency>
                <groupId>commons-logging</groupId>
                <artifactId>commons-logging</artifactId>
                <version>1.1.1</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-jpa</artifactId>
                <version>1.2.1.RELEASE</version>
            </dependency>
        </dependencies>
    
    
    	<!-- 打包需要的配置 -->
        <!--
    		maven-surefire-plugin:执行mvn命令时,执行应用程序的单元测试
    	-->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.19.1</version>
                    <configuration>
                        <suiteXmlFiles>
                            <suiteXmlFile>
                                src/main/resources/testng.xml
                            </suiteXmlFile>
                        </suiteXmlFiles>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    



    测试用例

    测试用例使用mysql数据库管理

    测试用例测试的接口接口描述
    logincase/v1/login登陆接口
    getuserinfocase/v1/getUserInfo获取用户信息接口
    getuserlistcase/v1/getUserInfo获取用户列表接口
    addusercase/v1/addUser添加用户接口
    updateuserinfocase/v1/updateUserInfo更新用户信息接口

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述


    配置

    mybatis配置文件

    databaseConfig.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    
        <settings>
            <!--mybatis一级缓存只对STATEMENT有效-->
            <setting name="localCacheScope" value="STATEMENT"/>
            <!--mybatis关闭二级缓存-->
            <setting name="cacheEnabled" value="false"/>
            <!--mybatis在控制台打印sql-->
            <setting name="logImpl" value="STDOUT_LOGGING" />
        </settings>
    
        <!-- 注册对象的空间命名 -->
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <!-- 1.加载数据库驱动 -->
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <!-- 2.数据库连接地址 -->
                    <property name="url" value="jdbc:mysql://localhost:3306/course?serverTimezone=UTC"/>
                    <!-- 数据库用户... -->
                    <property name="username" value="root"/>
                    <!-- 数据库密码... -->
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
    
        <!-- 注册映射文件:java对象与数据库之间的xml文件路径! -->
        <mappers>
            <mapper resource="mapper/SQLMapper.xml"/>
        </mappers>
    
    </configuration>
    

    testng基础配置

    testng.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
    
    <suite name="用户管理系统测试套件">
        <test name="用户管理系统测试用例">
    
    	</test>
    </suite>    
    

    配置应用程序属性文件

    application.properties

    test.url=http://localhost:8888
    
    #登陆接口uri
    login.uri=/v1/login
    
    #更新用户信息接口uri
    updateUserInfo.uri=/v1/updateUserInfo
    
    #获取用户列表接口uri
    getUserList.uri=/v1/getUserInfo
    
    #获取用户信息接口uri
    getUserInfo.uri=/v1/getUserInfo
    
    #添加用户接口uri
    addUser.uri=/v1/addUser
    
    # 设置生成日志
    logging.path=logs
    logging.file=caseTest.log
    
    


    model层

    将数据表中各个表的字段转换为Java bean对象
    在这里插入图片描述

    AddUserCase.java

    package com.course.model;
    
    import lombok.Data;
    
    /**
     * 添加用户接口的测试用例
     */
    @Data
    public class AddUserCase {
        private String userName;
        private String password;
        private String sex;
        private String age;
        private String permission;
        private String isDelete;
        private String expected;
    }
    
    

    GetUserInfoCase.java

    package com.course.model;
    
    import lombok.Data;
    
    /**
     * 获取用户信息的测试用例
     */
    @Data
    public class GetUserInfoCase {
        private int userId;
        private String expected;
    }
    
    
    

    GetUserListCase.java

    package com.course.model;
    
    import lombok.Data;
    
    /**
     * 获取用户列表
     */
    @Data
    public class GetUserListCase {
        private String userName;
        private String age;
        private String sex;
        private String expected;
    }
    
    

    InterfaceName.java
    创建一个枚举类,对应接口的名称

    package com.course.model;
    
    /**
     * 将需要测试的接口进行枚举,防止使用 测试范围外的非法接口
     */
    public enum InterfaceName {
    
        GETUSERLIST,LOGIN,UPDATEUSERINFO,GETUSERINFO,ADDUSERINFO
    
    }
    
    

    LoginCase.java

    package com.course.model;
    
    import lombok.Data;
    
    /**
     * 登录接口的测试用例
     */
    @Data
    public class LoginCase {
        private int id;
        private String userName;
        private String password;
        private String expected;
    }
    
    

    UpdateUserInfoCase.java

    package com.course.model;
    
    
    import lombok.Data;
    
    /**
     * 更新用户信息接口的测试用例
     */
    @Data
    public class UpdateUserInfoCase {
    
        private int id;
        private int userId;
        private String userName;
        private String sex;
        private String age;
        private String permission;
        private String isDelete;
        private String expected;
    
    }
    
    

    User.java

    package com.course.model;
    
    import lombok.Data;
    
    /**
     * 用户 Java Bean
     */
    @Data
    public class User {
        private int id;
        private String userName;
        private String password;
        private int age;
        private String sex;
        private int permission;
        private int isDelete;
    
        ///复写toString方法,用来处理json
        @Override
        public String toString(){
            return (
                    "id:"+id+","+
                    "userName:"+userName+","+
                    "password:"+password+","+
                    "age:"+age+","+
                    "sex:"+sex+","+
                    "permission:"+permission+","+
                    "isDelete:"+isDelete+"}"
            );
        }
    }
    
    


    config层

    创建测试报告类

    ExtentTestNGIReporterListener.java
    然后将报告加入监听

    package com.course.config;
    
    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 com.aventstack.extentreports.reporter.configuration.Theme;
    import org.testng.*;
    import org.testng.xml.XmlSuite;
    
    import java.io.File;
    import java.util.*;
    
    public class ExtentTestNGIReporterListener 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);
                    }
                }
    
            }
    //        for (String s : Reporter.getOutput()) {
    //            extent.setTestRunnerOutput(s);
    //        }
    
            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);
            //怎么样解决cdn.rawgit.com访问不了的情况?设置静态文件的DNS
            htmlReporter.config().setResourceCDN(ResourceCDN.EXTENTREPORTS);
    
            htmlReporter.config().setDocumentTitle("api自动化测试报告");
            htmlReporter.config().setReportName("api自动化测试报告");
            htmlReporter.config().setChartVisibilityOnOpen(true);
            htmlReporter.config().setTestViewChartLocation(ChartLocation.TOP);
            htmlReporter.config().setTheme(Theme.STANDARD);
            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();
                    }
                    if(name.length()>0){
                        if(name.length()>50){
                            name= name.substring(0,49)+"...";
                        }
                    }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();
        }
    }
    
    

    testng.xml

        <!--添加测试报告监听器-->
        <listeners>
            <listener class-name="com.course.config.ExtentTestNGIReporterListener"></listener>
        </listeners>
    

    获取用户配置基础信息

    创建TestConfig对象,对应application.properties中的接口名称

    TestConfig.java

    package com.course.config;
    
    import lombok.Data;
    import org.apache.http.client.CookieStore;
    import org.apache.http.impl.client.DefaultHttpClient;
    
    
    @Data
    public class TestConfig {
    
        //登陆接口uri
        public static String loginUrl;
        //更新用户信息接口uri
        public static String updateUserInfoUrl;
        //获取用户列表接口uri
        public static String getUserListUrl;
        //获取用户信息接口uri
        public static String getUserInfoUrl;
        //添加用户信息接口
        public static String addUserUrl;
    
        //声明http客户端
        public static DefaultHttpClient defaultHttpClient;
        //用来存储cookies信息的变量
        public static CookieStore store;
    
    }
    
    


    utils层

    拼接url工具类

    注意:工具类里的对象、方法,我们一般声明为静态方法static,不用new,直接用。

    ConfigFile.java

    package com.course.utils;
    
    import com.course.model.InterfaceName;
    
    import java.util.Locale;
    import java.util.ResourceBundle;
    
    /**
     * 读取application.properties文件,拼接测试接口URL
     */
    public class ConfigFile {
    
        private static ResourceBundle bundle= ResourceBundle.getBundle("application", Locale.CHINA);;
    
        //传进来的name,必须是我们设计的InterfaceName类中枚举的接口名,不能瞎传
        public static String getUrl(InterfaceName name){
            String address = bundle.getString("test.url");
            String uri = ""; //获取application.perperties中的uri
            String testUrl;  //最终的测试地址,address+uri
            if(name == InterfaceName.GETUSERLIST){
                uri = bundle.getString("getUserList.uri");
    
            }
    
            if(name == InterfaceName.LOGIN){
                uri = bundle.getString("login.uri");
            }
    
            if(name == InterfaceName.UPDATEUSERINFO){
                uri = bundle.getString("updateUserInfo.uri");
            }
    
            if(name == InterfaceName.GETUSERINFO){
                uri = bundle.getString("getUserInfo.uri");
            }
    
            if(name == InterfaceName.ADDUSERINFO){
                uri = bundle.getString("addUser.uri");
            }
            testUrl = address + uri;
            return testUrl;
        }
    }
    
    

    数据库工具类

    创建连接数据库的session

    DatabaseUtil.java

    package com.course.utils;
    
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    
    import java.io.IOException;
    import java.io.Reader;
    
    /**
     * 数据库工具类
     */
    public class DatabaseUtil {
    
        public static SqlSession getSqlSession() throws IOException {
            //获取配置的资源文件
            Reader reader = Resources.getResourceAsReader("databaseConfig.xml");
            //得到SqlSessionFactory,使用类加载器加载xml文件
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader);
            //得到sqlsession对象,这个对象就能执行配置文件中的sql语句啦
            SqlSession session = factory.openSession();
            return session;
        }
    }
    
    
    


    开发测试用例代码

    编写测试代码

    在这里插入图片描述
    AddUserTest.java

    package com.course.cases;
    
    import com.course.config.TestConfig;
    import com.course.model.AddUserCase;
    import com.course.model.User;
    import com.course.utils.DatabaseUtil;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.util.EntityUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.json.JSONObject;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Transactional;
    import org.testng.Assert;
    import org.testng.annotations.Test;
    
    import java.io.IOException;
    
    public class AddUserTest {
    
        //执行这个用例,前提需要登录成功!
        //所以需要依赖登录成功那个组
        @Test(dependsOnGroups = "loginTrue",description = "添加用户接口测试")
        @Transactional(isolation = Isolation.READ_UNCOMMITTED)
        public void addUser() throws IOException, InterruptedException {
            SqlSession session = DatabaseUtil.getSqlSession();
            System.out.println(session);
            AddUserCase addUserCase = session.selectOne("addUserCase", 1);
            System.out.println("测试数据为:"+ addUserCase.toString());
            System.out.println( "addUser的uri为:" + TestConfig.addUserUrl);
            //发请求,获取结果
            String result = getResult(addUserCase);
            //验证返回结果
            //session.commit();
            /*
            getResult调用接口,实际上是又开了一个进程,跟测试用例addUser()代码是并行运行的,
            这个时候就需要让测试代码休息一下,等待接口调用完毕后,再去查数据库的结果,否则可能查出来user为null
             */
            Thread.sleep(2000);
    
            User user = session.selectOne("addUser", addUserCase); //sql:查看新增加的user
            System.out.println("请求接口后,user表中新增的user为:" + user.toString());
    
            //处理结果,判断返回结果是否符合预期
            Assert.assertEquals(addUserCase.getExpected(), result);
        }
    
        private String getResult(AddUserCase addUserCase) throws IOException {
            HttpPost post = new HttpPost(TestConfig.addUserUrl);
            JSONObject param = new JSONObject();
            param.put("userName", addUserCase.getUserName());
            param.put("password", addUserCase.getPassword());
            param.put("sex", addUserCase.getSex());
            param.put("age", addUserCase.getAge());
            param.put("permission", addUserCase.getPermission());
            param.put("isDelete", addUserCase.getIsDelete());
            //设置头信息
            post.setHeader("content-type", "application/json");
            StringEntity entity = new StringEntity(param.toString(), "utf-8");
            post.setEntity(entity);
    
            //设置cookies
            TestConfig.defaultHttpClient.setCookieStore(TestConfig.store);
            String result; //存放返回结果
            HttpResponse response = TestConfig.defaultHttpClient.execute(post);
            result = EntityUtils.toString(response.getEntity(), "utf-8");
            System.out.println("请求响应结果为:" + result);
            return result;
        }
    }
    
    

    GetUserInfoListTest.java

    package com.course.cases;
    
    import com.course.config.TestConfig;
    import com.course.model.GetUserListCase;
    import com.course.model.User;
    import com.course.utils.DatabaseUtil;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.util.EntityUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.json.JSONArray;
    import org.json.JSONObject;
    import org.testng.Assert;
    import org.testng.annotations.Test;
    
    import java.io.IOException;
    import java.util.List;
    
    public class GetUserInfoListTest {
    
        @Test(dependsOnGroups = "loginTrue", description = "获取性别为男的用户信息")
        public void getUserListInfo() throws IOException {
            SqlSession session = DatabaseUtil.getSqlSession();
            GetUserListCase getUserListCase = session.selectOne("getUserListCase", 1);
            System.out.println(getUserListCase.toString());
            System.out.println(TestConfig.getUserListUrl);
    
            //第1步:发送请求,获取结果
            //实际结果
            JSONArray resultJSON = getJsonResult(getUserListCase);
    
            //第2步:验证
            List<User> userList = session.selectList(getUserListCase.getExpected(), getUserListCase);
            for (User u: userList){
                System.out.println("获取的user是" + u.toString());
            }
    
            //预期结果
            JSONArray userListJson = new JSONArray(userList);
    
            //判断获取用户的个数与预期是否相同
            Assert.assertEquals(userListJson.length(), resultJSON.length());
    
            //判断请求获取的每个用户信息与预期是否相同
            for (int i = 0; i < resultJSON.length(); i++){
                JSONObject expect = (JSONObject) resultJSON.get(i);
                JSONObject actual = (JSONObject) userListJson.get(i);
                Assert.assertEquals(expect.toString(), actual.toString());
    
            }
        }
    
        private JSONArray getJsonResult(GetUserListCase getUserListCase) throws IOException {
            HttpPost post = new HttpPost(TestConfig.getUserListUrl);
            JSONObject param = new JSONObject(); //设置json数据
            param.put("userName", getUserListCase.getUserName());
            param.put("sex", getUserListCase.getSex());
            param.put("age", getUserListCase.getAge());
    
            post.setHeader("content-type", "application/json"); //设置header
    
            StringEntity entity = new StringEntity(param.toString(), "utf-8");
            post.setEntity(entity); //设置entity
    
            TestConfig.defaultHttpClient.setCookieStore(TestConfig.store); //设置cookie
    
            HttpResponse response = TestConfig.defaultHttpClient.execute(post);
            String result = EntityUtils.toString(response.getEntity(), "utf-8");
            JSONArray jsonArray = new JSONArray(result);
    
            return jsonArray;
        }
    }
    
    

    GetUserInfoTest.java

    package com.course.cases;
    
    import com.course.config.TestConfig;
    import com.course.model.GetUserInfoCase;
    import com.course.model.User;
    import com.course.utils.DatabaseUtil;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.util.EntityUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.json.JSONArray;
    import org.json.JSONObject;
    import org.testng.Assert;
    import org.testng.annotations.Test;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    public class GetUserInfoTest {
    
    
        @Test(dependsOnGroups = "loginTrue", description = "获取userId为1的用户信息")
        public void getUerInfoTest() throws IOException {
            SqlSession session = DatabaseUtil.getSqlSession();
            GetUserInfoCase getUserInfoCase = session.selectOne("getUserInfoCase", 1);
            System.out.println(getUserInfoCase.toString());
            System.out.println(TestConfig.getUserInfoUrl);
    
            //发送请求
            //实际结果
            JSONArray resultJSON = getJsonResult(getUserInfoCase);
    
            //mapper id取getUserInfoCase中的expected字段,即获取预期的用户信息
            User user = session.selectOne(getUserInfoCase.getExpected(), getUserInfoCase);
    
            List userList = new ArrayList();
            userList.add(user);
            //预期结果
            JSONArray jsonArray = new JSONArray(userList);
    
            JSONArray jsonArray_res = new JSONArray(resultJSON.getString(0));
    
            //jsonArray与jsonArray_res内元素顺序可能不同,不能这样断言;可以将里面每个元素取出,逐个断言
            Assert.assertEquals(jsonArray.toString(), jsonArray_res.toString());
    
    
        }
    
        private JSONArray getJsonResult(GetUserInfoCase getUserInfoCase) throws IOException {
            HttpPost post = new HttpPost(TestConfig.getUserInfoUrl);
            JSONObject param = new JSONObject();
            param.put("id", getUserInfoCase.getUserId());
    
            post.setHeader("content-type", "application/json");
            StringEntity entity = new StringEntity(param.toString(), "utf-8");
            post.setEntity(entity);
    
            TestConfig.defaultHttpClient.setCookieStore(TestConfig.store);
            HttpResponse response = TestConfig.defaultHttpClient.execute(post);
    
            String result = EntityUtils.toString(response.getEntity(), "utf-8");
            List resultList = Arrays.asList(result);
            JSONArray array = new JSONArray(resultList);
            return array;
        }
    }
    
    

    LoginTest.java

    package com.course.cases;
    
    import com.course.config.TestConfig;
    import com.course.model.InterfaceName;
    import com.course.model.LoginCase;
    import com.course.utils.ConfigFile;
    import com.course.utils.DatabaseUtil;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.util.EntityUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.json.JSONObject;
    import org.testng.Assert;
    import org.testng.annotations.BeforeTest;
    import org.testng.annotations.Test;
    
    import java.io.IOException;
    
    public class LoginTest {
    
        @BeforeTest(groups = "loginTrue", description = "测试准备工作,获取httpclient对象")
        public void beforeTest(){
            TestConfig.getUserInfoUrl = ConfigFile.getUrl(InterfaceName.GETUSERINFO);
            TestConfig.getUserListUrl = ConfigFile.getUrl(InterfaceName.GETUSERLIST);
            TestConfig.addUserUrl = ConfigFile.getUrl(InterfaceName.ADDUSERINFO);
            TestConfig.loginUrl = ConfigFile.getUrl(InterfaceName.LOGIN);
            TestConfig.updateUserInfoUrl = ConfigFile.getUrl(InterfaceName.UPDATEUSERINFO);
            TestConfig.defaultHttpClient = new DefaultHttpClient();
    
        }
    
        @Test(groups = "loginTrue", description = "用户登录成功接口测试")
        public void loginTrue() throws IOException {
            SqlSession session = DatabaseUtil.getSqlSession();
            LoginCase loginCase = session.selectOne("loginCase", 1);//取xml文件中sql语句id为loginCase的,取数据库中id为1的数据
            System.out.println(loginCase.toString());
            System.out.println(TestConfig.loginUrl);
    
            //第1步:发送请求
            String result = getResult(loginCase);
            System.out.println(result);
            //验证结果
            Assert.assertEquals(loginCase.getExpected(), result);
        }
    
    
        @Test(groups = "loginFalse", description = "用户登录失败接口测试")
        public void loginFalse() throws IOException {
            SqlSession session = DatabaseUtil.getSqlSession();
            LoginCase loginCase = session.selectOne("loginCase", 2);//取xml文件中sql语句id为loginCase的,取数据库中id为2的数据
            System.out.println(loginCase.toString());
            System.out.println(TestConfig.loginUrl);
    
            //第1步:发送请求
            String result = getResult(loginCase);
            System.out.println(result);
            //验证结果
            Assert.assertEquals(loginCase.getExpected(), result);
        }
    
    
        private String getResult(LoginCase loginCase) throws IOException {
            HttpPost post = new HttpPost(TestConfig.loginUrl);
            JSONObject param = new JSONObject();
            param.put("userName", loginCase.getUserName());
            param.put("password", loginCase.getPassword());
    
            post.setHeader("content-type", "application/json");
            StringEntity entity = new StringEntity(param.toString(), "utf-8");
            post.setEntity(entity);
            String result;
            HttpResponse response = TestConfig.defaultHttpClient.execute(post);
            result = EntityUtils.toString(response.getEntity(), "utf-8");
            TestConfig.store = TestConfig.defaultHttpClient.getCookieStore();
            return result;
        }
    }
    
    

    UpdateUserInfoTest.java

    package com.course.cases;
    
    import com.course.config.TestConfig;
    import com.course.model.UpdateUserInfoCase;
    import com.course.model.User;
    import com.course.utils.DatabaseUtil;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.util.EntityUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.json.JSONObject;
    import org.testng.Assert;
    import org.testng.annotations.Test;
    
    import java.io.IOException;
    
    public class UpdateUserInfoTest {
    
        @Test(dependsOnGroups = "loginTrue", description = "更改用户信息接口测试用例")
        public void updateUserInfo() throws IOException, InterruptedException {
            SqlSession session = DatabaseUtil.getSqlSession();
            UpdateUserInfoCase updateUserInfoCase = session.selectOne("updateUserInfoCase", 1);
            System.out.println(updateUserInfoCase.toString());
            System.out.println(TestConfig.updateUserInfoUrl);
    
            int result = getResult(updateUserInfoCase);
    
            Thread.sleep(3000);
            session.commit();
            User user = session.selectOne(updateUserInfoCase.getExpected(), updateUserInfoCase);
    
            //判断user不为空
            Assert.assertNotNull(user);
            //判断result不为空
            Assert.assertNotNull(result);
        }
    
    
        @Test(dependsOnGroups = "loginTrue", description = "删除用户信息")
        public void deleteUser() throws IOException, InterruptedException {
            SqlSession session = DatabaseUtil.getSqlSession();
            UpdateUserInfoCase updateUserInfoCase = session.selectOne("updateUserInfoCase", 2);
            System.out.println(updateUserInfoCase.toString());
            System.out.println(TestConfig.updateUserInfoUrl);
    
            int result = getResult(updateUserInfoCase);
    
            Thread.sleep(3000);
            session.commit();
            User user = session.selectOne(updateUserInfoCase.getExpected(), updateUserInfoCase);
    
            //判断user不为空
            Assert.assertNotNull(user);
            Assert.assertNotNull(result);
        }
    
    
        private int getResult(UpdateUserInfoCase updateUserInfoCase) throws IOException {
            HttpPost post = new HttpPost(TestConfig.updateUserInfoUrl);
            //设置请求json
            JSONObject param = new JSONObject();
            param.put("id", updateUserInfoCase.getUserId());
            param.put("userName", updateUserInfoCase.getUserName());
            param.put("sex", updateUserInfoCase.getSex());
            param.put("age", updateUserInfoCase.getAge());
            param.put("permission", updateUserInfoCase.getPermission());
            param.put("isDelete", updateUserInfoCase.getIsDelete());
            //设置请求头信息
            post.setHeader("content-type", "application/json");
    
            //设置请求实体
            StringEntity entity = new StringEntity(param.toString(), "utf-8");
            post.setEntity(entity);
    
            //设置cookie
            TestConfig.defaultHttpClient.setCookieStore(TestConfig.store);
    
            String result;
            HttpResponse response = TestConfig.defaultHttpClient.execute(post);
            result = EntityUtils.toString(response.getEntity(), "utf-8");
    
            return Integer.parseInt(result);
        }
    
    }
    
    

    编写对应的sql

    SQLMapper.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!-- 命名空间mapper,如果有多个mapper文件,这个必须唯一 -->
    <mapper namespace="com.course.model">
    
        <!--获取登陆接口case-->
        <select id="loginCase" parameterType="Integer"  resultType="com.course.model.LoginCase">
    
            select * from loginCase
            where id = #{id};
        </select>
        <!--添加用户接口case-->
        <select id="addUserCase" parameterType="Integer" resultType="com.course.model.AddUserCase">
            select * from addUserCase where id=#{id};
        </select>
    
        <!--获取用户信息case-->
        <select id="getUserInfoCase" parameterType="Integer" resultType="com.course.model.GetUserInfoCase">
            <!-- SQL语句 -->
            select * from getUserInfoCase where id=#{id};
        </select>
    
        <!--获取用户列表case-->
        <select id="getUserListCase" parameterType="Integer" resultType="com.course.model.GetUserListCase">
            <!-- SQL语句 -->
            select * from getUserListCase where id=#{id};
        </select>
    
        <!--更新/删除用户信息case-->
        <select id="updateUserInfoCase" parameterType="Integer" resultType="com.course.model.UpdateUserInfoCase">
            select * from updateUserInfoCase where id = #{id};
        </select>
    
        <!--添加用户接口-->
    
        <select id="addUser" parameterType="com.course.model.AddUserCase" resultType="com.course.model.User" flushCache="false" useCache="false">
            select * from user where
            userName=#{userName}
            and password=#{password}
            and sex=#{sex}
            and age=#{age}
            and permission=#{permission}
            and isDelete=#{isDelete};
        </select>
    
        <!--获取用户信息-->
        <select id="getUserInfo" parameterType="com.course.model.GetUserInfoCase" resultType="com.course.model.User">
            <!-- SQL语句 -->
            select * from user where
            id=#{userId};
        </select>
    
        <!--获取用户列表-->
        <select id="getUserList" parameterType="com.course.model.GetUserListCase" resultType="com.course.model.User">
            <!-- SQL语句 -->
            select * from user
            <trim prefix="WHERE" prefixOverrides="and">
                <if test="null != userName and '' !=userName">
                    AND userName=#{userName}
                </if>
                <if test="null != sex and '' !=sex">
                    AND sex=#{sex}
                </if>
                <if test="null != age and '' !=age">
                    AND age=#{age}
                </if>
    
            </trim>
            ;
        </select>
    
        <!--获取更新后的数据-->
        <select id="getUpdateUserInfo" parameterType="com.course.model.UpdateUserInfoCase" resultType="com.course.model.User">
            select * from user
            <trim prefix="WHERE" prefixOverrides="and">
                <if test="null != userName and '' !=userName">
                    AND userName=#{userName}
                </if>
                <if test="null != sex and '' !=sex">
                    AND sex=#{sex}
                </if>
                <if test="null != age and '' !=age">
                    AND age=#{age}
                </if>
                <if test="null != permission and '' !=permission">
                    AND permission=#{permission}
                </if>
                <if test="null != isDelete and '' !=isDelete">
                    AND isDelete=#{isDelete}
                </if>
            </trim>
            And id = #{userId};
        </select>
    
    
    </mapper>
    

    把测试用例加入testng.xml

    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.course.cases.LoginTest">
                    <methods>
                        <include name="loginTrue"/>
                        <!--<include name="loginFalse"/>-->
                    </methods>
                </class>
                <class name="com.course.cases.AddUserTest">
                    <methods>
                        <include name="addUser"/>
                    </methods>
                </class>
                <class name="com.course.cases.GetUserInfoTest">
                    <methods>
                        <include name="getUserInfo"/>
                    </methods>
                </class>
                <class name="com.course.cases.GetUserInfoListTest">
                    <methods>
                        <include name="getUserListInfo"/>
                    </methods>
                </class>
                <class name="com.course.cases.UpdateUserInfoTest">
                    <methods>
                        <include name="updateUserInfo"/>
                        <include name="deleteUser"/>
                    </methods>
                </class>
                <class name="com.course.cases.wangTest">
                    <methods>
                        <include name="wangGetUser"/>
                    </methods>
                </class>
            </classes>
        </test>
    
        <!--添加测试报告监听器-->
        <listeners>
            <listener class-name="com.course.config.ExtentTestNGIReporterListener"></listener>
        </listeners>
    </suite>
    


    执行testng.xml

    查看测试用例执行情况
    在这里插入图片描述

    打jar包

    在terminal中,进入项目目录下,执行mvn clean package,所有测试用例执行成功的情况下,会在target目录下生成jar包
    注:我这里项目名称由requestTest改为interfaceTest了,大家进入自己的项目路径就可以。
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • Java接口自动化测试框架设计-2-Get请求方法和测试

    万次阅读 多人点赞 2018-05-22 00:11:42
    这篇开始,我来介绍通过代码逐步实现接口自动化测试框架的设计过程。先不要着急,框架设计我们只是介绍基本的组件,而且框架设计没有想象那么难,一步一步跟着做就会了。这篇我们来演示,如果通过Java代码来实现一个...
  • 无论是自动化测试还是自动化部署,撸码肯定少不了,所以下面的基于java语言的接口自动化测试,要想在业务上实现接口自动化,前提是要有一定的java基础。 如果没有java基础,也没关系。这里小编也为大家提供了一套...
  • 支持:yalm编写维护用例;数据库操作;自定义函数;变量参数化;可视化测试报告等。适合想接触0基础和刚接触的测试工程师
  • 第1章 接口自动化测试整体认知了解什么是接口和为什么要做接口测试。并且知道接口自动化测试应该学习哪些技术以及接口自动化测试的落地过程。 1-1 导学章节 1-2 什么是接口 1-3 为什么要做接口测试 试看 1-4 接口...
  • 比用selenium做功能自动化的性价比高,因为selenium在界面修改了内容后,维护成本比较高 环境异常一般是由运维那边配合完成 接口测试用例示例: 确认预期结果是否正常运行,查看日志来确定 ...
  • 本文来自于个人微博,在这篇文章中,我们将介绍一下开源的Web-API自动化测试框架——Karate.在这篇文章中,我们将介绍一下开源的Web-API自动化测试框架——KarateKarate是基于另一个BDD测试框架Cucumber来建立的,...
  • java开发接口自动化测试jar包(初步) java开发接口自动化测试jar包(初步) 项目信息 成果展示 使用前 结果 增强的字节码内容 执行流程图: asm相关部分 代理模式启动流程图 ControllerAdapter or ...
  • 前面说过了,如果你稍微懂得TestNG这个单元测试框架,到目前这个简单的Java接口自动化测试框架主体的骨架部分已经完成设计并实现。这篇,继前篇的基础上,把测试用例中获取响应状态码和响应数据转换成JSON格式这些...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 278,692
精华内容 111,476
关键字:

java接口自动化测试登录接口

java 订阅