走進Java接口測試之從0到1搭建數據驅動框架(用例管理)

前言

先吐個槽,參加過很多技術大會,也看過個很多技術類文章,發現大部分存在一個通病,即:都會提問題,提思路,但是都不會講具體的落地方案,所以我寫東西給自己定了一個目標,即:能夠落地,儘量提供一個小而簡單的 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 是 IntelliJ IDEA 2018
在這裏插入圖片描述
引包,配置 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 參數化驅動用例運行,實現測試腳本和數據的解耦;

至此,我們要實現接口用例集中式管理功能,也算是完成了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章