0
点赞
收藏
分享

微信扫一扫

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

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


前言

先吐个槽,参加过很多技术大会,也看过个很多技术类文章,发现大部分存在一个通病,即:都会提问题,提思路,但是都不会讲具体的落地方案,所以我写东西给自己定了一个目标,即:能够落地,尽量提供一个小而简单的 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: 走进Java接口测试之从0到1搭建数据驱动框架(用例管理)_SQL_02引包,配置 pom.xml:

    1. <dependencies>
    2.         <!--MyBatis、数据库驱动、数据库连接池-->
    3.         <dependency>
    4.             <groupId>org.mybatis.spring.boot</groupId>
    5.             <artifactId>mybatis-spring-boot-starter</artifactId>
    6.             <version>2.1.1</version>
    7.         </dependency>
    8. 
    9.         <!--MySQL驱动-->
    10.         <dependency>
    11.             <groupId>mysql</groupId>
    12.             <artifactId>mysql-connector-java</artifactId>
    13.             <scope>runtime</scope>
    14.         </dependency>
    15. 
    16.         <dependency>
    17.             <groupId>org.projectlombok</groupId>
    18.             <artifactId>lombok</artifactId>
    19.             <optional>true</optional>
    20.         </dependency>
    21. 
    22.         <dependency>
    23.             <groupId>org.springframework.boot</groupId>
    24.             <artifactId>spring-boot-starter-test</artifactId>
    25.             <scope>test</scope>
    26.             <exclusions>
    27.                 <exclusion>
    28.                     <groupId>org.junit.vintage</groupId>
    29.                     <artifactId>junit-vintage-engine</artifactId>
    30.                 </exclusion>
    31.             </exclusions>
    32.         </dependency>
    33. 
    34.         <!--引入 testng 测试框架-->
    35.         <dependency>
    36.             <groupId>org.testng</groupId>
    37.             <artifactId>testng</artifactId>
    38.             <version>6.14.3</version>
    39.             <scope>compile</scope>
    40.         </dependency>
    41. 
    42.     </dependencies>

    全部代码骨架结构


    1. ├─logs
    2. │  └─spring-boot-logback             # 日志文件
    3. │          all_api-test-logback.log # 所有日志
    4. │          err_api-test-logback.log # 错误日志
    5. ├─src
    6. │  ├─main
    7. │  │  ├─java
    8. │  │  │  └─com
    9. │  │  │      └─zuozewei
    10. │  │  │          └─springbootdatadrivendemo
    11. │  │  │              │  SpringbootDataDrivenDemoApplication.java # 启动类
    12. │  │  │              │  
    13. │  │  │              ├─db
    14. │  │  │              │  ├─auto      # 存放MyBatis Generator生成器生成的数据层代码,可以随时删除再生成
    15. │  │  │              │  │  ├─mapper # DAO 接口
    16. │  │  │              │  │  └─model  # Entity 实体
    17. │  │  │              │  └─manual    # 存放自定义的数据层代码,包括对MyBatis Generator自动生成代码的扩展
    18. │  │  │              │      ├─mapper # DAO 接口
    19. │  │  │              │      └─model  # Entity 实体
    20. │  │  │              ├─handler  # 数据转换
    21. │  │  │              └─service # 业务逻辑
    22. │  │  │                  └─impl # 实现类
    23. │  │  │                          
    24. │  │  └─resources
    25. │  │      │  application.yml       # 全局配置文件
    26. │  │      │  generatorConfig.xml # Mybatis Generator 配置文件
    27. │  │      │  logback-spring.xml     # logback 配置文件
    28. │  │      │  spy.properties      # P6Spy 配置文件
    29. │  │      │  
    30. │  │      ├─db
    31. │  │      ├─mapper
    32. │  │      │  └─com
    33. │  │      │      └─zuozewei
    34. │  │      │          └─springbootdatadrivendemo
    35. │  │      │              └─db
    36. │  │      │                  ├─auto      # 存放MyBatis Generator生成器生成的数据层代码,可以随时删除再生成
    37. │  │      │                  │  └─mapper # 数据库 Mapping 文件
    38. │  │      │                  │          
    39. │  │      │                  └─manual    # 存放自定义的数据层代码,包括对MyBatis Generator自动生成代码的扩展
    40. │  │      │                      └─mapper # 数据库 Mapping 文件
    41. │  │      └─testng
    42. │  │          │  APICollection-TestSuite.xml # 所用测试用例集
    43. │  │          └─jdbcbapi
    44. │  │                  jdbcAPI-TestSuite.xml  # 某API测试用例集
    45. │  │                  
    46. │  └─test
    47. │      └─java
    48. │          └─com
    49. │              └─zuozewei
    50. │                  └─springbootdatadrivendemo
    51. │                      └─demo   # 接口测试用例
    52. ├─pom.xml

    测试用例管理

    MySQL数据库

    创建测试用例表:


    1. CREATE DATABASE /*!32312 IF NOT EXISTS*/`autotest` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_vietnamese_ci */;
    2. 
    3. USE `autotest`;
    4. 
    5. /*Table structure for table `api_testdata_demo` */
    6. 
    7. DROP TABLE IF EXISTS `api_testdata_demo`;
    8. 
    9. CREATE TABLE `api_testdata_demo` (
    10.   `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT '测试ID',
    11.   `Protocol` enum('Http','RPC','jdbc') DEFAULT NULL COMMENT '协议',
    12.   `Category` enum('Webapi','db') DEFAULT NULL COMMENT '接口类别',
    13.   `Method` varchar(128) DEFAULT NULL COMMENT '接口名称',
    14.   `Parameters` varchar(1000) DEFAULT NULL COMMENT '参数',
    15.   `expected` varchar(128) DEFAULT NULL COMMENT '检查点',
    16.   `description` varchar(1000) DEFAULT NULL COMMENT '描述',
    17.   `isRun` enum('1','0') DEFAULT NULL COMMENT '运行状态,1:运行,0:未运行',
    18.   PRIMARY KEY (`id`)
    19. ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
    20. 
    21. /*Data for the table `api_testdata_demo` */
    22. 
    23. insert  into `api_testdata_demo`(`id`,`Protocol`,`Category`,`Method`,`Parameters`,`expected`,`description`,`isRun`) values (1,'jdbc','db','demo','latte','CNY 25.00','测试demo','1');

    创建完成大概是这样: 走进Java接口测试之从0到1搭建数据驱动框架(用例管理)_spring_03 这里的 SQL 主要决定了选取哪些测试用例进行测试: 走进Java接口测试之从0到1搭建数据驱动框架(用例管理)_SQL_04


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

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

    持久层开发

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

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

    Mapper.xml

    编写对应的 TestDataMapper.xml:


    1. <?xml version="1.0" encoding="UTF-8" ?>
    2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    3. <mapper namespace="com.zuozewei.springbootdatadrivendemo.db.manual.mapper.TestDataMapper" >
    4. 
    5.     <!-- 自定义SQL语句 -->
    6.     <select id="selectBysql" parameterType="String"   resultType="java.util.LinkedHashMap">
    7.         ${value};
    8.     </select>
    9. 
    10. </mapper>

    注意:

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

    Dao接口

    dao 层增加 TestDataMapper.java:


    1. /**
    2.  * 描述:
    3.  * 自定义sql查询
    4.  *
    5.  * @author zuozewei
    6.  * @create 2019-11-21 21:18
    7.  */
    8. 
    9. public interface TestDataMapper {
    10. 
    11.     // 自定义sql查询
    12.     List<LinkedHashMap<String, Object>> selectBysql(String sql);
    13. 
    14. }

    Service 的接口 TestDataService :


    1. /**
    2.  * 描述: TestDataService
    3.  *
    4.  * @author zuozewei
    5.  * @create 2019-11-21 18:00
    6.  */
    7. 
    8. public interface TestDataService {
    9. 
    10.     // 自定义查询
    11.     List<LinkedHashMap<String, Object>> selectBysql(String sql);
    12. 
    13. }

    实现 Service 的接口调用方法:


    1. /**
    2.  * 描述: 参数化自定义查询实现类
    3.  *
    4.  * @author zuozewei
    5.  * @create 2019-11-21 16:04
    6.  */
    7. 
    8. 
    9. @Service
    10. public class TestDataServiceImpl implements TestDataService {
    11. 
    12.     @Resource
    13.     private TestDataMapper testDataMapper;
    14. 
    15.     @Override
    16.     public List<LinkedHashMap<String, Object>> selectBysql(String sql) {
    17.         return testDataMapper.selectBysql(sql);
    18.     }
    19. 
    20. }

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


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

    脚本参数化

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

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

    1. <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
    2. 
    3. <suite name="jdbc 测试" verbose="1" preserve-order="true" >
    4. 
    5. <test name="测试demo" preserve-order="true">
    6.     <parameter name="sql"
    7.                value="SELECT * FROM autotest.api_testdata_demo
    8.                     WHERE Protocol = 'jdbc'
    9.                     AND Category = 'db'
    10.                     AND Method = 'demo'
    11.                     AND isRun = 1;"/>
    12. 
    13.     <classes>
    14.         <class name="com.zuozewei.springbootdatadrivendemo.demo.TestMapperService"/>
    15.     </classes>
    16. </test>
    17. 
    18. <!--<listeners>-->
    19. <!--<listener class-name="com.zuozewei.springbootdatadrivendemo.demo.listener.ExtentTestNGIReporterListener"/>-->
    20. <!--</listeners>-->
    2. </suite>
    

    解释一下配置文件:

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

    编写脚本代码 TestMapperService.java:

    1. @SpringBootTest
    2. @Slf4j
    3. public class TestMapperService extends AbstractTestNGSpringContextTests {
    4. 
    5.     private String sql; // SQL参数
    6. 
    7.     @Autowired
    8.     private TestDataService testDataService;
    9. 
    10.     @Parameters({"sql"})
    11.     @BeforeClass
    12.     public void beforeClass(String sql) {
    13.         this.sql = sql;
    14.     }
    15. 
    16.     /**
    17.      * XML中的SQL决定了执行什么用例, 执行多少条用例, SQL的搜索结果为需要测试的测试用例
    18.      */
    19. 
    20.     @DataProvider(name = "testData")
    21.     private Object[][] getData() {
    22.         List<LinkedHashMap<String, Object>> results = testDataService.selectBysql(sql);
    23.         Object[][] objects = new Object[results.size()][];
    24.         for (int i = 0; i < results.size(); i++) {
    25.             objects[i] = new Object[]{results.get(i)};
    26.         }
    27.         return objects;
    28. 
    29.     }
    30. 
    31.     @Test(dataProvider = "testData",description = "测试demo")
    32.     public void testSelect(Map<String, String> data) throws InterruptedException {
    33.         //  to do something...
    34.     }
    35. 
    36. }

    注意:

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

    工程结构

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

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

    小结

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

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

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


    举报

    相关推荐

    0 条评论