美團接口自動化測試實踐

1、概述

1.1 接口自動化概述

衆所周知,接口自動化測試有着以下特色:前端

  • 低投入,高產出。
  • 比較容易實現自動化。
  • 和UI自動化測試相比更加穩定。

如何作好一個接口自動化測試項目呢?java

我認爲,一個「好的」自動化測試項目,須要從「時間」「人力」「收益」這三個方面出發,作好「取捨」。mysql

不能因爲被測系統發生一些變動,就致使花費了幾個小時的自動化腳本沒法執行。同時,咱們須要看到「收益」,不能爲了總想看到100%的成功,而少作或者不作校驗,可是校驗多了維護成本必定會增多,可能天天都須要進行大量的維護。git

因此作好這三個方面的平衡並不容易,常常能看到作自動化的同窗,作到最後就本末倒置了。github

 

1.2 提升ROI

想要提升ROI(Return On Investment,投資回報率),咱們必須從兩方面入手:web

  1. 減小投入成本。
  2. 增長使用率。

 

針對「減小投入成本」

咱們須要作到:正則表達式

  • 減小工具開發的成本。儘量的減小開發工具的時間、工具維護的時間,儘量使用公司已有的,或是業界成熟的工具或組件。
  • 減小用例錄入成本。簡化測試用例錄入的成本,儘量多的提示,若是能夠,開發一些批量生成測試用例的工具。
  • 減小用例維護成本。減小用例維護成本,儘可能只用在頁面上作簡單的輸入便可完成維護動做,而不是進行大量的代碼操做。
  • 減小用例優化成本。當團隊作用例優化時,能夠經過一些統計數據,進行有針對性、有目的性的用例優化。

 

針對「增長使用率」

咱們須要作到:sql

  • 手工也能用。不僅是進行接口自動化測試,也能夠徹底用在手工測試上。
  • 人人能用。每個須要使用測試的人,包括一些非技術人員均可以使用。
  • 當工具用。將一些接口用例當成工具使用,好比「生成訂單」工具,「查找表單數據」工具。
  • 天天測試。進行每日構建測試。
  • 開發的在構建以後也能觸發測試。開發將被測系統構建後,能自動觸發接口自動化測試腳本,進行測試。

因此,我這邊開發了Lego接口測試平臺,來實現我對自動測試想法的一些實踐。先簡單瀏覽一下網站,瞭解一下大概是個什麼樣的工具。數據庫

首頁:
imagejson

用例維護頁面:
image

自動化用例列表:
image

在線執行結果:
image

用例數量統計:
image

 

1.3 Lego的組成

Lego接口測試解決方案是由兩部分組成的,一個就是剛剛看到的「網站」,另外一個部分就是「腳本」。

下面就開始進行「腳本設計」部分的介紹。

 

2、腳本設計

2.1 Lego的作法

Lego接口自動化測試腳本部分,使用很常見的Jenkins+TestNG的結構。

image

相信看到這樣的模型並不陌生,由於不少的測試都是這樣的組成方式。

將自動化測試用例存儲至MySQL數據庫中,作成比較常見的「數據驅動」作法。

不少團隊也是使用這樣的結構來進行接口自動化,沿用的話,那在之後的「推廣」中,學習和遷移成本低都會比較低。

 

2.2 測試腳本

首先來簡單看一下目前的腳本代碼:

public class TestPigeon { String sql; int team_id = -1; @Parameters({"sql", "team_id"}) @BeforeClass() public void beforeClass(String sql, int team_id) { this.sql = sql; this.team_id = team_id; ResultRecorder.cleanInfo(); } /** * XML中的SQL決定了執行什麼用例, 執行多少條用例, SQL的搜索結果爲須要測試的測試用例 */ @DataProvider(name = "testData") private Iterator<Object[]> getData() throws SQLException, ClassNotFoundException { return new DataProvider_forDB(TestConfig.DB_IP, TestConfig.DB_PORT, TestConfig.DB_BASE_NAME,TestConfig.DB_USERNAME, TestConfig.DB_PASSWORD, sql); } @Test(dataProvider = "testData") public void test(Map<String, String> data) { new ExecPigeonTest().execTestCase(data, false); } @AfterMethod public void afterMethod(ITestResult result, Object[] objs) {...} @AfterClass public void consoleLog() {...} } 

image

有一種作法我一直不提倡,就是把測試用例直接寫在Java文件中。這樣作會帶來不少問題:修改測試用例須要改動大量的代碼;代碼也不便於交接給其餘同窗,由於每一個人都有本身的編碼風格和用例設計風格,這樣交接,最後都會變成由下一個同窗所有推翻重寫一遍;若是測試平臺更換,沒法作用例數據的遷移,只能手動的一條條從新輸入。

因此「測試數據」與「腳本」分離是很是有必要的。

網上不少的範例是使用的Excel進行的數據驅動,我這裏爲何改用MySQL而不使用Excel了呢?

在公司,咱們的腳本和代碼都是提交至公司的Git代碼倉庫,若是使用Excel……很顯然不方便平常常常修改測試用例的狀況。使用MySQL數據庫就沒有這樣的煩惱了,因爲數據與腳本的分離,只需對數據進行修改便可,腳本每次會在數據庫中讀取最新的用例數據進行測試。同時,還能夠防止一些操做代碼時的誤操做。

這裏再附上一段我本身寫的DataProvider_forDB方法,方便其餘同窗使用在本身的腳本上:

import java.sql.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 數據源 數據庫
 *
 * @author yongda.chen
 */
public class DataProvider_forDB implements Iterator<Object[]> {

    ResultSet rs;
    ResultSetMetaData rd;

    public DataProvider_forDB(String ip, String port, String baseName, 
        String userName, String password, String sql) throws ClassNotFoundException, SQLException {

        Class.forName("com.mysql.jdbc.Driver");
        String url = String.format("jdbc:mysql://%s:%s/%s", ip, port, baseName);
        Connection conn = DriverManager.getConnection(url, userName, password);
        Statement createStatement = conn.createStatement();

        rs = createStatement.executeQuery(sql);
        rd = rs.getMetaData();
    }

    @Override
    public boolean hasNext() {
        boolean flag = false;
        try {
            flag = rs.next();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return flag;
    }

    @Override
    public Object[] next() {
        Map<String, String> data = new HashMap<String, String>();
        try {
            for (int i = 1; i <= rd.getColumnCount(); i++) {
                data.put(rd.getColumnName(i), rs.getString(i));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        Object r[] = new Object[1];
        r[0] = data;
        return r;
    }

    @Override
    public void remove() {
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

 

2.3 配置文件

上面圖中提到了「配置文件」,下面就來簡單看一下這個XML配置文件的腳本:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Pigeon Api測試" parallel="false"> <test name="xxx-xxx-service"> <parameter name="sql" value="SELECT * FROM API_PigeonCases WHERE team_id=2 AND isRun=1 AND service='xxx-xxx-service' AND env='beta';"/> <classes> <class name="com.dp.lego.test.TestPigeon"/> </classes> </test> <listeners> <listener class-name="org.uncommons.reportng.HTMLReporter"/> <listener class-name="org.uncommons.reportng.JUnitXMLReporter"/> </listeners> </suite> 

image

對照上圖來解釋一下配置文件:

  • SQL的話,這裏的SQL主要決定了選取哪些測試用例進行測試。
  • 一個標籤,就表明一組測試,能夠寫多個標籤。
  • 「listener」是爲了最後可以生成一個ReportNG的報告。
  • Jenkins來實現每日構建,可使用Maven插件,經過命令來選擇須要執行的XML配置。

 

這樣作有什麼好處呢?

使用SQL最大的好處就是靈活

image

如上面的這個例子,在數據庫中會查詢出下面這56條測試用例,那麼這個標籤就會對這56條用例進行逐一測試。

 

多標籤時,能夠分組展現

image

使用多個標籤來區分用例,最大的好處就是也能在最後的報告上,達到一個分組展現的效果。

 

報告更美觀豐富

image

因爲使用了ReportNG進行報告的打印,因此報告的展現要比TestNG自帶的報告要更加美觀、而且能自定義展現樣式,點開能看到詳細的執行過程。

image

若是有執行失敗的用例,一般報錯的用例會在最上方優先展現。

 

支持多團隊

image

當兩個團隊開始使用時,爲了方便維護,將基礎部分抽出,各個團隊的腳本都依賴這個Base包,而且將Base包版本置爲「SNAPSHOT版本」。使用「SNAPSHOT版本」的好處是,以後我對Lego更新,各個業務組並不須要對腳本作任何改動就能及時更新。

 

當更多的團隊開始使用後,比較直觀的看的話是這個樣子的:

image

每一個團隊的腳本都依賴於個人這個Base包,因此最後,各個業務團隊的腳本就變成了下面的這個樣子:

image

能夠看到,使用了Lego以後:

  • 沒有了Java文件,只有XML文件
  • xml中只須要配置SQL。
  • 執行和調試也很方便。
  • 能夠右鍵直接執行想要執行的測試配置。
  • 可使用maven命令執行測試:
    • mvn clean test -U -Dxml=xmlFileName 。
    • 經過參數來選擇須要執行的xml文件。
  • 也可使用Jenkins來實現定時構建測試。

因爲,全部測試用例都在數據庫因此這段腳本基本不須要改動了,減小了大量的腳本代碼量。

有些同窗要問,有時候編寫一條接口測試用例不僅是請求一下接口就行,可能還須要寫一些數據庫操做啊,一些參數可能還得本身寫一些方法才能獲取到啊之類的,那不code怎麼處理呢?

下面就進入「用例設計」,我將介紹我如何經過統一的用例模板來解決這些問題。

 

3、用例設計

3.1 一些思考

我在作接口自動化設計的時候,會思考通用、校驗、健壯、易用這幾點。

 

通用

  • 簡單、方便
    • 用例數據與腳本分離,簡單、方便。
    • 免去上傳腳本的動做,能避免不少沒必要要的錯誤和維護時間。
    • 便於維護。
  • 模板化
    • 抽象出通用的模板,可快速拓展。
    • 數據結構一致,便於批量操做。
    • 專人維護、減小多團隊間的重複開發工做。
    • 因爲使用了統一的模板,那各組之間即可交流、學習、作有效的對比分析。
    • 若是之後這個平臺再也不使用,或者有更好的平臺,可快速遷移。
  • 可統計、可拓展
    • 可統計、可開發工具;如:用例數統計,某服務下有多少條用例等。
    • 可開發用例維護工具。
    • 可開發批量生成工具。

 

校驗

在寫自動化腳本的時候,都會想「細緻」,而後「寫不少」的檢查點;但當「校驗點」多的時候,又會由於不少緣由形成執行失敗。因此咱們的設計,須要在保證充足的檢查點的狀況下,還要儘量減小誤報。

  • 充足的檢查點
    • 能夠檢查出被測服務更多的缺陷。
  • 儘可能少的誤報
    • 能夠減小不少的人工檢查和維護的時間人力成本。
  • 還要
    • 簡單、易讀。
    • 最好使用一些公式就能實現本身想要的驗證。
    • 通用、靈活、多樣。
    • 甚至能夠用在其餘項目的檢查上,減小學習成本。

 

健壯

執行測試的過程當中,不免會報失敗,執行失敗可能的緣由有不少,簡單分爲4類:

image

  • 被測系統出錯,這部分實際上是咱們但願看到的,由於這說明咱們的自動化測試真正地發現了一個Bug,用例發揮了它的價值,因此,這是咱們但願看到的。
  • 測試工具出錯,這部分實際上是咱們不但願看到的,由於很大可能咱們今天的自動化至關於白跑了。
  • 測試數據錯誤,這是咱們要避免的,既然數據容易失效,那我在設計測試平臺的時候,就須要考慮若是將全部的數據跑「活」,而不是隻寫「死」。
  • 不可抗力,這部分是咱們也很無奈的,可是這樣的狀況不多發生。

那針對上面的狀況:

  • 參數數據失效
    • 支持實時去數據庫查詢。
    • 支持批量查。
  • IP進場發生變動
    • 自動更新IP。
  • 靈活、可複用
    • 支持批量維護。
    • 接口測試執行前生成一些數據。
    • 接口執行完成後銷燬一些數據。
    • 支持參數使用另外一條測試用例的返回結果。
    • 支持一些請求參數實時生成,如token等數據,從而減小數據失效的問題。

經過這些手段,提升測試用例的健壯性,讓每一條自動化測試用例都能很好的完成測試任務,真正發揮出一條測試用例的價值。

 

易用

  • 簡單
    • 功能強大,但要人人會用。
    • 非技術人員也要會用。
  • 減小代碼操做
    • 讓自動化開發人員注意力能更多的放在用例自己,而不是浪費在可有可無的開發工做上面。
  • 還要
    • 配置能複用。
    • 通用、易學。
    • 一些數據能自動生成。

 

3.2 Lego接口自動化測試用例

說了這麼多,那咱們來看一下一條Lego接口測試用例的樣子。

一條Lego自動用例執行順序大概是以下圖這樣:

image

簡單區分一下各個部分,能夠看到:

image

那上面圖中提到了兩個名詞:

  • 「參數化」
  • 「先後置動做」

下面會先對這兩個名詞作一個簡單的介紹。

 

3.3 參數化

好比一個請求須要用到的參數。

{
    "sync": false, "cityId": 1, "source": 0, "userId": 1234, "productId": 00004321 } 

這個例子中有個參數"productId": 00004321,而因爲測試的環境中,表單00004321極可能一些狀態已經發生了改變,甚至表單已經刪除,致使接口請求的失敗,那麼這時候,就很適合對"productId": 00004321進行參數化,好比寫成這樣:

{
    "sync": false,
    "cityId": 1,
    "source": 0,
    "userId": 1234,
    "productId": ${myProductId}
}

因此對「參數化」簡單的理解就是:

經過一些操做,將一個「值」替換掉測試用例裏的一個「替代字符」

${myProductId} 的值能夠經過配置獲取到:

  • Key-Value
    • 配置 Value=00004321。
  • SQL獲取
    • 執行一個select語句來實時查詢獲得可用ID。
  • 已有測試用例
    • 某個接口接口測試用例的返回結果。

 

「參數化」實例

下面咱們來看一個「參數化」的實例:

(1) 首先咱們在參數化維護頁面中新建一個參數化,shopdealid

image

經過配置咱們能夠看到這個參數的值,是執行了一條SQL後,取用執行結果中DealID字段的值。

(2) 在用例中,將須要這個表單號的地方用${shopdealid}替代。

image

那在編寫測試用例的時候,你們能夠看一下這個放大的圖片,在這裏的ProductID的值並非硬代碼一個固定的表單號,而是選擇了剛纔配置的參數化數據。

(3) 執行結果中,${shopdealid} 變爲實時查詢數據庫的來的一個真實的表單號。

image

從結果中能夠看到,咱們的這個參數被替換成了一個有效的值,而這個值就是咱們剛剛配置的那個SQL實時查詢而來的。

 

「參數化」的場景

多個測試用例使用同一個參數進行測試

如50條測試用例都使用同一個id做爲參數進行測試,這時候咱們須要變動這個id。

無參數化時:

  • 須要修改50次,即每條測試用例中的id都得進行修改。
  • 可能會有遺漏。
    有參數化時:
  • id部分用 ${myID} 替代。
  • 須要修改的話,在「參數化維護」頁面中維護 ${myID}這條數據就能夠。修改一次,全部使用${myID}的用例都配置完成。

 

測試數據過時致使測試用例執行失敗

如一條用例參數須要傳入token,可是Token會由於時間問題而致使過時,這時候用例就失敗了。

無參數化時:

  • 常常修改Token,或是寫一段id轉Token的代碼。
  • 方法可能會重複編寫。
  • 多個團隊之間可能實現方式也不一樣。

有參數化時:

  • 使用參數化工具,Lego統一管理。
  • 維護一個參數化 如:${測試用Token} = id:123

 

數據庫獲取有效測試數據

參數中須要傳入DealId做爲參數,寫死參數的話,若是這個DealId被修改引發失效,那這條測試用例就會執行失敗。

不使用Lego時:

  • 測試環境中,一個訂單時常會由於測試須要被修改數據,致使單號失效,最後致使自動化失敗。
  • 編寫相關代碼來作好數據準備工做。
  • 在代碼中編寫讀取數據庫的方法獲取某些內容。

在Lego上的方案:

  • 使用參數化,實時獲取sql結果,查詢出一條符合條件的dealId來實現。
  • 使用參數化,調用寫好的「生成訂單」接口用例實現,拿單號來實現。
  • 先後置動做,插入一條知足條件的數據。

 

3.4 先後置動做

「先後置動做」的概念就比較好理解了:

在接口請求以前(或以後),執行一些操做

目前先後置動做支持6種類型:

  • 數據庫SQL執行
    • 有時候在執行接口請求前,爲了保證數據可用,可能須要在數據庫中插入或刪除一條信息,這時候就可使用先後置動做裏的「執行SQL語句」類型,來編寫在接口請求前(後)的 Insert 和 Delete 語句。
  • 已有測試用例執行
    • 好比當前測試用例的請求參數,須要使用另外一條測試用例的返回結果,這時候就可使用「執行測試用例」類型,寫上Lego上某條測試用例的ID編號,就能夠在當前用例接口請求前(後)執行這條測試用例。
    • 先後置動做中測試用例的返回結果能夠用於當前用例的參數,對測試用例返回結果內容的獲取上,也支持JsonPath和正則表達式兩種方式。
  • MQ消息發送
    • 在接口請求前(後)發送MQ消息。
  • HTTP請求
  • 等待時間
  • 自定義的Java方法
    • 若是上面的方法還知足不了需求,還能夠根據本身的須要,編寫本身的Java方法。
    • 能夠在Lego-Kit項目中,編寫本身須要的Java方法,選擇「執行Java方法」,經過反射實現自定義Java方法的執行。

這裏的SQL同時支持Select操做,這裏其實也是作了一些小的設計,會將查詢出來的所有的結果,放入到這個全局Map中。 

好比查詢一條SQL獲得下表中的結果:

id    name       age       number   
0 張三 18 1122
1 李四 30 3344

那咱們可使用下面左邊的表達式,獲得對應的結果:

  • ${pre.name} ---- 獲得 「張三」å
  • ${pre.age} ---- 獲得 18
  • ${pre.number} ---- 獲得 1122

也能夠用:

  • ${pre.name[0]} ---- 獲得 「張三」
  • ${pre.age[0]} ---- 獲得 18
  • ${pre.number[0]} ---- 獲得 1122
  • ${pre.name[1]} ---- 獲得 「李四」
  • ${pre.age[1]} ---- 獲得 30
  • ${pre.number[1]} ---- 獲得 3344

這樣的設計,更加幫助在用例設計時,提供數據準備的操做。

 

「先後置動做」實例

(1) 首先咱們在先後置維護頁面中新建一個動做,獲取庫存上限未賣光團單 。

image

這個配置也是能夠支持在線調試的,在調試中,能夠看到可使用的參數化:

image

(2) 在測試用例中的前置動做,添加獲取庫存上限未賣光團單 。

image

這樣就能夠在整個測試用例中,使用${pre.ProductID},來替換掉原有的數據信息。

(3) 最後請求接口,返回了執行成功 。 

image

Q & A

Q:那若是一樣是獲取三個參數,使用3個「參數化的Select操做」和使用1個「前置動做的Select操做」又有什麼不一樣呢?

A: 不一樣在於執行時間上。
好比,咱們查詢最新的有效團單的「單號」「下單人」和「手機號」三個字段。
使用3個「參數化的Select操做」:可能當執行${單號}的時候獲得的訂單號是「10001」,可是當執行到${下單人}的時候,可能有誰又下了一單,可能取到的下單人變成了「10002」的「李四」而不是「10001」的「張三」了,最後可能「單號」「下單人」和「手機號」三個字段去的數據並不是同一行的數據。
而使用「前置動做的Select操做」:就能夠避免上面的問題,由於全部字段的數據是一次性查詢出來的,就不會出現錯位的狀況。

Q : 那「參數化的Select操做」和「前置動做的Select操做」這樣不一樣的取值時機又有什麼好用之處呢?

A : 因爲「前置動做」必定是接口請求前執行,「參數化」必定是用到的時候才執行這樣的特性。
因此在檢查點中,若是要驗證一個數據庫字段在通過接口調用後發生了變動,那使用「前置動做」和「參數化」同時去查詢這個字段,而後進行比較,不一致就說明發生了變化。
因此根據使用場景,選擇合適的參數化方式,很重要,選擇對了,能大大提高測試用例的測試數據健壯性。

 

3.5 執行各部分

回到一開始的流程圖,能夠按照一類一類來看執行過程。

 

測試發起

image

測試發起基本仍是使用的Jenkins,穩定、成熟、簡單、公司工具組支持,也支持從Lego的Web頁面進行執行操做。

 

數據 / 環境準備

image

使用 @DataProvider 的方式,從DB數據庫中讀取測試用例,逐一執行進行測試。

 

測試執行

image

在正式執行測試用例以前,會先進行一波參數替換的動做,在調用接口以後,還會執行一次參數替換動做。

image

參數替換後會進行前置動做的執行,而後在調用接口以後還會執行測試後動做,最後執行後置動做。

image

接口請求這部分就沒什麼好說的了,就是經過接口請求的參數,請求對應的接口,拿到返回結果。

這裏的話是爲了方便通用,因此要求返回的結果都是使用的String類型。這樣作最大的好處就是。好比說我如今有一種新的接口類型須要接入。那隻須要寫一個方法可以請求到這個接口,而且拿到String類型的返回結果,就能夠很快將新的接口類型接入Lego測試平臺進行接口測試。 

 

檢查點校驗

image

檢查點部分是一條自動化測試用例的精髓,一條自動化測試用例是否能真正的發揮它的測試功能,就是看QA對這條測試用例的檢查點編寫是否作了良好設計。在Lego平臺上,目前我擁有的檢查點有6種不一樣的類型。

  • 異常檢查點
    • 當返回結果爲異常時,則會報錯。
    • 可是有時候爲了作異常測試,能夠將這個檢查點關掉。
  • 不爲空檢查點
    • 顧名思義,當出現""、"[]"、"{}"、null 這樣的的結果,都會報錯。也能夠根據本身用例的實際狀況關閉。
  • 包含檢查點
  • 不包含檢查點
    • 「包含」和「不包含」檢查點是將接口的返回結果做爲一個String類型來看,檢查全部返回內容中是否「包含」或「不包含」指定的內容。
  • 數據庫參數檢查點
    • 顧名思義,不作過多的解釋了。
  • JsonPath檢查點
    • 這是我在Lego上設計的最具備特點的一種檢查點類型。

JsonPath的基本寫法是{JsonPath語法}==value

JsonPath的語法和XPath的語法差很少,都是根據路徑的方法找值。這裏也是主要是針對返回結果爲JSON數據的結果,進行檢查。

具體的JsonPath語法能夠參考:https://github.com/json-path/JsonPath

說完了"JsonPath的語法",如今說一下"JsonPath檢查點的語法""JsonPath檢查點的語法"是我本身想的,主要針對如下幾種數據類型進行校驗:

 

(1) 字符串類型結果檢驗

  • 等於:==
  • 不等於:!==
  • 包含:=
  • 不包含:!=

例如:

  • {$.[1].name}==aa:檢查返回的JSON中第2個JSON的name字段是否等於aa。
  • {$..type}=='14':檢查返回的JSON中每個JSON的name字段是否等於aa。
  • {$.[1].type}==14 && {$.[1].orderId}==106712:一條用例中多個檢查用&&鏈接。
  • {$..orderId}!==12:檢查返回的JSON中每一個JSON的orderId字段是否不等於12。
  • {$..type}=1:檢查返回的JSON中每一個JSON的type字段是否包含1。
  • {$.[1].type}!=chenyongda:檢查返回的JSON中第2個JSON的type字段是否不包含chenyongda。

 

(2) 數值校驗

  • 等於:=
  • 大於:>
  • 大於等於:>=
  • 小於:<
  • 小於等於:<=

例如:

  • {$.[0].value}<5:檢查返回的JSON中第1個JSON的value字段的列表是否小於3。
  • {$.[1].value}>4:檢查返回的JSON中第2個JSON的value字段的列表是否大於4。

 

(3) List結果檢驗

  • list長度:.length
  • list包含:.contains(param)
  • list成員:.get(index)

例如:

  • {$..value}.length=3:檢查返回的JSON中每一個JSON的value字段的列表是否等於3。
  • {$.[0].value}.length<5:檢查返回的JSON中第1個JSON的value字段的列表是否小於3。
  • {$.[1].value}.length>4:檢查返回的JSON中第2個JSON的value字段的列表是否大於4。
  • {$..value}.contains('222'):檢查返回的JSON中每一個JSON的value字段的列表是否包含222字符串。
  • {$.[0].value}.contains(1426867200000):檢查返回的JSON中第1個JSON的value字段的列表是否包含1426867200000。
  • {$.[0].value}.get(0)=='222':檢查返回的JSON中第1個JSON的value字段的列表中第1個內容是否等於222。
  • {$..value}.get(2)='22':檢查返回的JSON中每一個JSON的value字段的列表中第3個內容是否包含22。

 

(4) 時間類型處理

時間戳轉日期時間字符串:.todate

例如:

  • {$..beginDate}.todate==2015-12-31 23:59:59:檢查返回的JSON中beginDate這個時間戳轉換成日期後是否等於2015-12-31 23:59:59。

 

當JsonPath返回的結果是列表的形式時

檢查點 檢查點等號左邊 指望值 驗證效果
{$.value}=="good" ['good', 'good', 'bad', 'good'] "good" 做爲4個檢查點,會拿列表裏的每一個對象逐一和「指望值」進行檢驗,每一次對比都是一個獨立的檢查點。
{$.value}==["good"] ['good', 'good', 'bad', 'good'] ["good"] 做爲1個檢查點,做爲一個總體作全量比對。
{$.value}==['a', 'b'] [['a', 'b'],['a', 'b'],['a', 'b', 'c']] ['a', 'b'] 做爲3個檢查點,道理和1同樣,列表中的數據分別和指望值作比較。

 

除此以外,還有很是多的花樣玩法

JsonPath中的檢查支持「參數化」和「先後置動做」,因此會看到不少如:

{$.param}='${param}' && {$.param}==${pre.param}

這樣的檢查點:

「參數化」和「先後置動做」也支持遞歸配置,這些都是爲了可以讓接口自動化測試用例寫的更加靈活好用。

 

測試結果

image

使用ReportNG能夠打印出很漂亮的報告。

報告會自定義一些高亮等展現方式,只須要在ReportNG使用前加上下面的語句,就能夠支持「輸出逃逸」,可以使用HTML標籤自定義輸出樣式。

System.setProperty("org.uncommons.reportng.escape-output", "false"); 

 

後期優化

image

當使用Jenkins執行後,經過Jenkins API 、和Base包中的一些方法,定時獲取測試結果,落數據庫,提供生成統計圖表用。

 

4、網站功能

4.1 站點開發

既然打算作工具平臺了,就得設計方方面面,惋惜人手和時間上的不足,只能我一人利用下班時間進行開發。也算是擔任了Lego平臺的產品、後端開發、前端開發、運維和測試等各類角色。

Jenkins+TestNG+ReportNG+我本身開發的基本接口自動化測試Base jar包,基本上沒什麼太大難度。可是站點這塊,在來美團以前,還真沒開發過這樣的工具平臺,這個算是個人第一個帶Web界面的工具。邊Google邊作,沒想到不久還真的架起來了一個簡易版本。

使用 Servlet + Jsp 進行開發,前端框架使用Bootstrap,前端數據使用jstl,數據庫使用MySQL,服務器使用的公司的一臺Beta環境Docker虛擬機,域名是申請的公司內網域名,並開通北京上海兩側內網訪問權限。

功能上基本都是要知足的,界面上,雖然作不到驚豔吧,可是絕對不能醜,功能知足,可是長得一副80年代的界面,我本身都會嫌棄去使用它,因此界面上我仍是花了一些時間去調整和設計。熟練之後就快多了。

 

4.2 總體組成

image

目前Lego由五個不一樣的項目組成,分別是「測試腳本」、「Lego-web頁面項目」、「用於執行接口測試的base包」、「小工具集合Lego-kit」和「lego-job」,經過上圖能夠看出各項目間的依賴關係。

細化各個項目的功能,就是下圖:

image

簡單來講,網站部分和腳本是分離的,中間的紐帶是數據庫。因此,沒有網站,腳本執行一點問題也沒有;一樣的,網站的操做,和腳本也沒有關係。

 

4.3 使用-平常維護

Step 1

image

天天上班來會收到這樣的測試郵件,經過郵件能知道昨晚執行的狀況。若是有報錯,能夠點擊「詳細報告連接」,跳轉到在線報告。

 

Step 2

image

在現報告能夠直接看到執行報錯的信息,而後點擊「LEGO維護傳送門」,能夠跳轉到Lego站點上,進行用例維護。

 

Step 3

跳轉到站點上之後,能夠直接展現出該條測試用例的全部信息。定位,維護、保存,維護用例,能夠點擊「執行」查看維護後的執行結果,維護好後「保存」便可。

僅僅3步,1~2分鐘便可完成對一條執行失敗的用例進行定位、調試和維護動做。

 

4.4 用例編輯

image

經過頁面,咱們就能夠對一條測試用例進行:

  • 新建
  • 複製
  • 編輯
  • 刪除
  • 是否放入每日構建中進行測試

 

4.5 在線調試

image

lego-web項目一樣的使用base進行的用例執行,因此執行結果和打印都與腳本執行的一致的。

 

4.6 用例生成工具

爲了更方便的寫用例,針對部分接口開發了一鍵批量生成用例的小工具。

 

4.7 執行結果分析

經過Jenkins接口、Base包中基礎Test方法,將結果收集到數據庫,便於各組對測試結果進行分析。

image

這是天天執行後成功率走勢圖:

image

也能夠按月進行統計,生成統計的圖表,幫助各個團隊進行月報數據收集和統計。

 

4.8 失敗緣由跟蹤

有了能直觀看到測試結果的圖表,就會想要跟蹤失敗緣由。

image

因此在成功率數據的右邊,會有這樣的跟蹤失敗緣由的入口,也能夠很直觀地看到哪一些失敗的緣由尚未被跟蹤。點開後能夠對失敗緣由進行記錄。

image

最後會有生成圖表,能夠很清晰地看到失敗緣由以及失敗類型的佔比。

 

4.9 代碼覆蓋率分析

結合Jacoco,咱們能夠對接口自動化的代碼覆蓋率進行分析。

image

在多臺Slave機器上配置Jacoco仍是比較複雜的,因此能夠開發覆蓋率配置輔助工具來幫助測試同窗,提升效率。 

image

 

4.10 用例優化方向

除了上面的圖表,還會給用例優化提供方向。

image
經過用例數量統計的圖表,咱們能夠知道哪些服務用例還比較少,哪些環境的用例還比較少,能夠比較有針對性的進行測試用例的補充。

image
經過失敗緣由的圖表,咱們能夠改善本身用例中的「參數化」和「先後置動做」的使用,增長測試用例的健壯性。

image
經過線上接口調用量排序的圖表。咱們能夠有效的知道優先維護哪些服務的測試用例,經過表格中,咱們能夠看到,哪些服務已經覆蓋了測試用例,哪些沒有被覆蓋, 給各組的QA制定用例開發計劃,提供參考。

image
同時在維護接口自動化測試的時候,都會看到用例評分的狀況,來協助QA提升用例編寫的質量。

 

4.11 收集反饋/學習

還作了「需求白板」,用來收集使用者的需求和Bug。除此以外,Lego平臺已經不僅是一個接口測試的平臺,還可讓想學習開發的QA領任務,學習一些開發技巧,提升本身的代碼能力。

 

5、總結

  1. 爲了減小開發成本,使用比較常見的Jenkins+TestNG的腳本形式。
  2. 爲了簡化code操做,使用DB進行測試用例存儲,並抽象出用例摸版。
  3. 爲了減低新建用例成本,開發「用例維護頁面」和「一鍵生成」等工具。
  4. 爲了減低維護成本,加跳轉連接,維護一條用例成本在幾分鐘內。
  5. 爲了增長用例健壯性,設計了「參數化」、「先後置動做」等靈活的參數替換。
  6. 爲了易用和兼容,統一「返回結果」類型,統一「檢查點」的使用。
  7. 爲了接口自動化用例設計提供方向,結合Jacoco作代碼覆蓋率統計,並開發相關配置工具
  8. 爲了便於分析數據,從DOM、CAT、Jenkins上爬各類數據,在頁面上用圖表展現。
  9. 爲了優化用例,提供「用例打分」、「線上調用量排行」等數據進行輔助。
相關文章
相關標籤/搜索