前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >走进Java接口测试之从0到1搭建数据驱动框架(用例管理)

走进Java接口测试之从0到1搭建数据驱动框架(用例管理)

作者头像
高楼Zee
发布2019-12-10 11:36:17
5090
发布2019-12-10 11:36:17
举报
文章被收录于专栏:7DGroup7DGroup

前言

先吐个槽,参加过很多技术大会,也看过个很多技术类文章,发现大部分存在一个通病,即:都会提问题,提思路,但是都不会讲具体的落地方案,所以我写东西给自己定了一个目标,即:能够落地,尽量提供一个小而简单的 Demo 让感兴趣的同学能快速上手。好了,这里啰嗦两句,下面进入正题。

在上两篇中,我们先介绍了需求功能,然后讲解了大概的框架设计,今天这篇主要看用例管理功能怎么落地去实现。

走进Java接口测试之从0到1搭建数据驱动框架(需求篇)

走进Java接口测试之从0到1搭建数据驱动框架(设计篇)

开发环境

  • SUN JDK1.8及以上
  • Maven 3.5.4及以上
  • IntelliJ IDEA 2018及以上
  • windows/macOS
  • Git 不限
  • MySQL 5.7及以上
  • Navicat Premium 11.2.7及以上 或 SQLyog 11.3及以上

新建Spring Boot项目

这里使用的 IDE 是 IntelliJIDEA2018

引包,配置 pom.xml:

<dependencies>
        <!--MyBatis、数据库驱动、数据库连接池-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>

        <!--MySQL驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--引入 testng 测试框架-->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.14.3</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>

全部代码骨架结构

├─logs
│  └─spring-boot-logback             # 日志文件
│          all_api-test-logback.log # 所有日志
│          err_api-test-logback.log # 错误日志
├─src
│  ├─main
│  │  ├─java
│  │  │  └─com
│  │  │      └─zuozewei
│  │  │          └─springbootdatadrivendemo
│  │  │              │  SpringbootDataDrivenDemoApplication.java # 启动类
│  │  │              │  
│  │  │              ├─db
│  │  │              │  ├─auto      # 存放MyBatis Generator生成器生成的数据层代码,可以随时删除再生成
│  │  │              │  │  ├─mapper # DAO 接口
│  │  │              │  │  └─model  # Entity 实体
│  │  │              │  └─manual    # 存放自定义的数据层代码,包括对MyBatis Generator自动生成代码的扩展
│  │  │              │      ├─mapper # DAO 接口
│  │  │              │      └─model  # Entity 实体
│  │  │              ├─handler  # 数据转换
│  │  │              └─service # 业务逻辑
│  │  │                  └─impl # 实现类
│  │  │                          
│  │  └─resources
│  │      │  application.yml       # 全局配置文件
│  │      │  generatorConfig.xml # Mybatis Generator 配置文件
│  │      │  logback-spring.xml     # logback 配置文件
│  │      │  spy.properties      # P6Spy 配置文件
│  │      │  
│  │      ├─db
│  │      ├─mapper
│  │      │  └─com
│  │      │      └─zuozewei
│  │      │          └─springbootdatadrivendemo
│  │      │              └─db
│  │      │                  ├─auto      # 存放MyBatis Generator生成器生成的数据层代码,可以随时删除再生成
│  │      │                  │  └─mapper # 数据库 Mapping 文件
│  │      │                  │          
│  │      │                  └─manual    # 存放自定义的数据层代码,包括对MyBatis Generator自动生成代码的扩展
│  │      │                      └─mapper # 数据库 Mapping 文件
│  │      └─testng
│  │          │  APICollection-TestSuite.xml # 所用测试用例集
│  │          └─jdbcbapi
│  │                  jdbcAPI-TestSuite.xml  # 某API测试用例集
│  │                  
│  └─test
│      └─java
│          └─com
│              └─zuozewei
│                  └─springbootdatadrivendemo
│                      └─demo   # 接口测试用例
├─pom.xml

测试用例管理

MySQL数据库

创建测试用例表:

CREATE DATABASE /*!32312 IF NOT EXISTS*/`autotest` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_vietnamese_ci */;

USE `autotest`;

/*Table structure for table `api_testdata_demo` */

DROP TABLE IF EXISTS `api_testdata_demo`;

CREATE TABLE `api_testdata_demo` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '测试ID',
  `Protocol` enum('Http','RPC','jdbc') DEFAULT NULL COMMENT '协议',
  `Category` enum('Webapi','db') DEFAULT NULL COMMENT '接口类别',
  `Method` varchar(128) DEFAULT NULL COMMENT '接口名称',
  `Parameters` varchar(1000) DEFAULT NULL COMMENT '参数',
  `expected` varchar(128) DEFAULT NULL COMMENT '检查点',
  `description` varchar(1000) DEFAULT NULL COMMENT '描述',
  `isRun` enum('1','0') DEFAULT NULL COMMENT '运行状态,1:运行,0:未运行',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

/*Data for the table `api_testdata_demo` */

insert  into `api_testdata_demo`(`id`,`Protocol`,`Category`,`Method`,`Parameters`,`expected`,`description`,`isRun`) values (1,'jdbc','db','demo','latte','CNY 25.00','测试demo','1');

创建完成大概是这样:

这里的 SQL 主要决定了选取哪些测试用例进行测试:

SELECT * FROM autotest.api_testdata_demo
WHERE Protocol = 'jdbc'
AND Category = 'db'
AND Method = 'demo'
AND isRun = 1;

注意:SQL 取用例是非常灵活,可以根据自己的业务调整表结构。

持久层开发

这里使用 mybatis 直接使用原生的 SQL 查询测试用例的数据。

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

Mapper.xml

编写对应的 TestDataMapper.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 namespace="com.zuozewei.springbootdatadrivendemo.db.manual.mapper.TestDataMapper" >

    <!-- 自定义SQL语句 -->
    <select id="selectBysql" parameterType="String"   resultType="java.util.LinkedHashMap">
        ${value};
    </select>

</mapper>

注意:

  • 这里是使用的是 ${},而不是 #{},这是因为如果我们使用 #{} 的时候,MyBatis 会自动帮我们把我们的字段自动加上单引号',使用 ${} 的时候就不会;
  • 使用 java.util.LinkedHashMap 作为返回类型,可以保持结果集本来的字段顺序。
Dao接口

dao 层增加 TestDataMapper.java:

/**
 * 描述:
 * 自定义sql查询
 *
 * @author zuozewei
 * @create 2019-11-21 21:18
 */

public interface TestDataMapper {

    // 自定义sql查询
    List<LinkedHashMap<String, Object>> selectBysql(String sql);

}

Service 的接口 TestDataService :

/**
 * 描述: TestDataService
 *
 * @author zuozewei
 * @create 2019-11-21 18:00
 */

public interface TestDataService {

    // 自定义查询
    List<LinkedHashMap<String, Object>> selectBysql(String sql);

}

实现 Service 的接口调用方法:

/**
 * 描述: 参数化自定义查询实现类
 *
 * @author zuozewei
 * @create 2019-11-21 16:04
 */


@Service
public class TestDataServiceImpl implements TestDataService {

    @Resource
    private TestDataMapper testDataMapper;

    @Override
    public List<LinkedHashMap<String, Object>> selectBysql(String sql) {
        return testDataMapper.selectBysql(sql);
    }

}

为了避免出现值 null 的列,不能被保存到 LinkedHashMap 对象 中,需要在 application.yml 的配置文件中 mybatis 如下配置:

mybatis:
  configuration:
    call-setters-on-nulls: true # 调用setter null,返回空也必须设置到bean中(直接执行sql专用)

脚本参数化

脚本参数化主要使用 TestNG 的 @DataProvider & Testng.xml

首先我们在resource下创建一个 testng 配置文件:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="jdbc 测试" verbose="1" preserve-order="true" >

<test name="测试demo" preserve-order="true">
    <parameter name="sql"
               value="SELECT * FROM autotest.api_testdata_demo
                    WHERE Protocol = 'jdbc'
                    AND Category = 'db'
                    AND Method = 'demo'
                    AND isRun = 1;"/>

    <classes>
        <class name="com.zuozewei.springbootdatadrivendemo.demo.TestMapperService"/>
    </classes>
</test>

<!--<listeners>-->
<!--<listener class-name="com.zuozewei.springbootdatadrivendemo.demo.listener.ExtentTestNGIReporterListener"/>-->
<!--</listeners>-->
</suite>

解释一下配置文件:

  • SQL的话,这里的SQL主要决定了选取哪些测试用例进行测试。
  • 一个标签,就代表一组测试,可以写多个标签。
  • “listener”是为了最后能够生成一个报告。

编写脚本代码 TestMapperService.java:

@SpringBootTest
@Slf4j
public class TestMapperService extends AbstractTestNGSpringContextTests {

    private String sql; // SQL参数

    @Autowired
    private TestDataService testDataService;

    @Parameters({"sql"})
    @BeforeClass
    public void beforeClass(String sql) {
        this.sql = sql;
    }

    /**
     * XML中的SQL决定了执行什么用例, 执行多少条用例, SQL的搜索结果为需要测试的测试用例
     */

    @DataProvider(name = "testData")
    private Object[][] getData() {
        List<LinkedHashMap<String, Object>> results = testDataService.selectBysql(sql);
        Object[][] objects = new Object[results.size()][];
        for (int i = 0; i < results.size(); i++) {
            objects[i] = new Object[]{results.get(i)};
        }
        return objects;

    }

    @Test(dataProvider = "testData",description = "测试demo")
    public void testSelect(Map<String, String> data) throws InterruptedException {
        //  to do something...
    }

}

注意:

  • SpringBoot 中使用 TestNg 必须加上 @SpringBootTest,并且继承 AbstractTestNGSpringContextTests,如果不继承AbstractTestNGSpringContextTests,会导致 @Autowired 不能加载 Bean。
  • @Parameters({"sql"}):从 xml 配置文件中获取 SQL语句;
  • @DataProvider 的数据来源是 MySQL;
  • @Test:测试逻辑地方。

工程结构

最后,用例管理的工程结构大概是以下的样子:

小结

在今天这篇文章中,主要基于 SpringBoot 框架的能力,和大家分享了实现一个用例管理的过程。在实现过程中,你最需要关注的几部分内容是:

  • 使用目前的主流 SpringBoot 2.2.0 作为项目的主体框架;
  • 使用 Maven 作为构建项目,方便管理依赖的 JAR 包;
  • 使用 MySQL 集中式管理测试用例,结构化数据;
  • 使用 TestNG 作为测试框架,强大的参数化功能,方便执行测试脚本;
  • MySQL 数据库管理测试用例,SQL 参数化驱动用例运行,实现测试脚本和数据的解耦;

至此,我们要实现接口用例集中式管理功能,也算是完成了。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-12-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 7DGroup 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 开发环境
  • 新建Spring Boot项目
  • 全部代码骨架结构
  • 测试用例管理
    • MySQL数据库
      • 持久层开发
        • Mapper.xml
        • Dao接口
      • 脚本参数化
      • 工程结构
      • 小结
      相关产品与服务
      云数据库 SQL Server
      腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档