1.1 接口自動化概述
衆所周知,接口自動化測試有着以下特色:前端
- 低投入,高產出。
- 比較容易實現自動化。
- 和UI自動化測試相比更加穩定。
如何作好一個接口自動化測試項目呢?java
我認爲,一個「好的」自動化測試項目,須要從「時間」、「人力」、「收益」這三個方面出發,作好「取捨」。mysql
不能因爲被測系統發生一些變動,就致使花費了幾個小時的自動化腳本沒法執行。同時,咱們須要看到「收益」,不能爲了總想看到100%的成功,而少作或者不作校驗,可是校驗多了維護成本必定會增多,可能天天都須要進行大量的維護。git
因此作好這三個方面的平衡並不容易,常常能看到作自動化的同窗,作到最後就本末倒置了。github
1.2 提升ROI
想要提升ROI(Return On Investment,投資回報率),咱們必須從兩方面入手:web
- 減小投入成本。
- 增長使用率。
針對「減小投入成本」
咱們須要作到:正則表達式
- 減小工具開發的成本。儘量的減小開發工具的時間、工具維護的時間,儘量使用公司已有的,或是業界成熟的工具或組件。
- 減小用例錄入成本。簡化測試用例錄入的成本,儘量多的提示,若是能夠,開發一些批量生成測試用例的工具。
- 減小用例維護成本。減小用例維護成本,儘可能只用在頁面上作簡單的輸入便可完成維護動做,而不是進行大量的代碼操做。
- 減小用例優化成本。當團隊作用例優化時,能夠經過一些統計數據,進行有針對性、有目的性的用例優化。
針對「增長使用率」
咱們須要作到:sql
- 手工也能用。不僅是進行接口自動化測試,也能夠徹底用在手工測試上。
- 人人能用。每個須要使用測試的人,包括一些非技術人員均可以使用。
- 當工具用。將一些接口用例當成工具使用,好比「生成訂單」工具,「查找表單數據」工具。
- 天天測試。進行每日構建測試。
- 開發的在構建以後也能觸發測試。開發將被測系統構建後,能自動觸發接口自動化測試腳本,進行測試。
因此,我這邊開發了Lego接口測試平臺,來實現我對自動測試想法的一些實踐。先簡單瀏覽一下網站,瞭解一下大概是個什麼樣的工具。數據庫
首頁:json
用例維護頁面:
自動化用例列表:
在線執行結果:
用例數量統計:
1.3 Lego的組成
Lego接口測試解決方案是由兩部分組成的,一個就是剛剛看到的「網站」,另外一個部分就是「腳本」。
下面就開始進行「腳本設計」部分的介紹。
2、腳本設計
2.1 Lego的作法
Lego接口自動化測試腳本部分,使用很常見的Jenkins+TestNG的結構。
相信看到這樣的模型並不陌生,由於不少的測試都是這樣的組成方式。
將自動化測試用例存儲至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() {...} }
有一種作法我一直不提倡,就是把測試用例直接寫在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>
對照上圖來解釋一下配置文件:
- SQL的話,這裏的SQL主要決定了選取哪些測試用例進行測試。
- 一個標籤,就表明一組測試,能夠寫多個標籤。
- 「listener」是爲了最後可以生成一個ReportNG的報告。
- Jenkins來實現每日構建,可使用Maven插件,經過命令來選擇須要執行的XML配置。
這樣作有什麼好處呢?
使用SQL最大的好處就是靈活
如上面的這個例子,在數據庫中會查詢出下面這56條測試用例,那麼這個標籤就會對這56條用例進行逐一測試。
多標籤時,能夠分組展現
使用多個標籤來區分用例,最大的好處就是也能在最後的報告上,達到一個分組展現的效果。
報告更美觀豐富
因爲使用了ReportNG
進行報告的打印,因此報告的展現要比TestNG自帶的報告要更加美觀、而且能自定義展現樣式,點開能看到詳細的執行過程。
若是有執行失敗的用例,一般報錯的用例會在最上方優先展現。
支持多團隊
當兩個團隊開始使用時,爲了方便維護,將基礎部分抽出,各個團隊的腳本都依賴這個Base包,而且將Base包版本置爲「SNAPSHOT版本」。使用「SNAPSHOT版本」的好處是,以後我對Lego更新,各個業務組並不須要對腳本作任何改動就能及時更新。
當更多的團隊開始使用後,比較直觀的看的話是這個樣子的:
每一個團隊的腳本都依賴於個人這個Base包,因此最後,各個業務團隊的腳本就變成了下面的這個樣子:
能夠看到,使用了Lego以後:
- 沒有了Java文件,只有XML文件
- xml中只須要配置SQL。
- 執行和調試也很方便。
- 能夠右鍵直接執行想要執行的測試配置。
- 可使用maven命令執行測試:
mvn clean test -U -Dxml=xmlFileName
。- 經過參數來選擇須要執行的xml文件。
- 也可使用Jenkins來實現定時構建測試。
因爲,全部測試用例都在數據庫因此這段腳本基本不須要改動了,減小了大量的腳本代碼量。
有些同窗要問,有時候編寫一條接口測試用例不僅是請求一下接口就行,可能還須要寫一些數據庫操做啊,一些參數可能還得本身寫一些方法才能獲取到啊之類的,那不code怎麼處理呢?
下面就進入「用例設計」,我將介紹我如何經過統一的用例模板來解決這些問題。
3、用例設計
3.1 一些思考
我在作接口自動化設計的時候,會思考通用、校驗、健壯、易用這幾點。
通用
- 簡單、方便
- 用例數據與腳本分離,簡單、方便。
- 免去上傳腳本的動做,能避免不少沒必要要的錯誤和維護時間。
- 便於維護。
- 模板化
- 抽象出通用的模板,可快速拓展。
- 數據結構一致,便於批量操做。
- 專人維護、減小多團隊間的重複開發工做。
- 因爲使用了統一的模板,那各組之間即可交流、學習、作有效的對比分析。
- 若是之後這個平臺再也不使用,或者有更好的平臺,可快速遷移。
- 可統計、可拓展
- 可統計、可開發工具;如:用例數統計,某服務下有多少條用例等。
- 可開發用例維護工具。
- 可開發批量生成工具。
校驗
在寫自動化腳本的時候,都會想「細緻」,而後「寫不少」的檢查點;但當「校驗點」多的時候,又會由於不少緣由形成執行失敗。因此咱們的設計,須要在保證充足的檢查點的狀況下,還要儘量減小誤報。
- 充足的檢查點
- 能夠檢查出被測服務更多的缺陷。
- 儘可能少的誤報
- 能夠減小不少的人工檢查和維護的時間人力成本。
- 還要
- 簡單、易讀。
- 最好使用一些公式就能實現本身想要的驗證。
- 通用、靈活、多樣。
- 甚至能夠用在其餘項目的檢查上,減小學習成本。
健壯
執行測試的過程當中,不免會報失敗,執行失敗可能的緣由有不少,簡單分爲4類:
- 被測系統出錯,這部分實際上是咱們但願看到的,由於這說明咱們的自動化測試真正地發現了一個Bug,用例發揮了它的價值,因此,這是咱們但願看到的。
- 測試工具出錯,這部分實際上是咱們不但願看到的,由於很大可能咱們今天的自動化至關於白跑了。
- 測試數據錯誤,這是咱們要避免的,既然數據容易失效,那我在設計測試平臺的時候,就須要考慮若是將全部的數據跑「活」,而不是隻寫「死」。
- 不可抗力,這部分是咱們也很無奈的,可是這樣的狀況不多發生。
那針對上面的狀況:
- 參數數據失效
- 支持實時去數據庫查詢。
- 支持批量查。
- IP進場發生變動
- 自動更新IP。
- 靈活、可複用
- 支持批量維護。
- 接口測試執行前生成一些數據。
- 接口執行完成後銷燬一些數據。
- 支持參數使用另外一條測試用例的返回結果。
- 支持一些請求參數實時生成,如token等數據,從而減小數據失效的問題。
經過這些手段,提升測試用例的健壯性,讓每一條自動化測試用例都能很好的完成測試任務,真正發揮出一條測試用例的價值。
易用
- 簡單
- 功能強大,但要人人會用。
- 非技術人員也要會用。
- 減小代碼操做
- 讓自動化開發人員注意力能更多的放在用例自己,而不是浪費在可有可無的開發工做上面。
- 還要
- 配置能複用。
- 通用、易學。
- 一些數據能自動生成。
3.2 Lego接口自動化測試用例
說了這麼多,那咱們來看一下一條Lego接口測試用例的樣子。
一條Lego自動用例執行順序大概是以下圖這樣:
簡單區分一下各個部分,能夠看到:
那上面圖中提到了兩個名詞:
- 「參數化」
- 「先後置動做」
下面會先對這兩個名詞作一個簡單的介紹。
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
。
經過配置咱們能夠看到這個參數的值,是執行了一條SQL後,取用執行結果中DealID
字段的值。
(2) 在用例中,將須要這個表單號的地方用${shopdealid}替代。
那在編寫測試用例的時候,你們能夠看一下這個放大的圖片,在這裏的ProductID的值並非硬代碼一個固定的表單號,而是選擇了剛纔配置的參數化數據。
(3) 執行結果中,${shopdealid} 變爲實時查詢數據庫的來的一個真實的表單號。
從結果中能夠看到,咱們的這個參數被替換成了一個有效的值,而這個值就是咱們剛剛配置的那個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) 首先咱們在先後置維護頁面中新建一個動做,獲取庫存上限未賣光團單
。
這個配置也是能夠支持在線調試的,在調試中,能夠看到可使用的參數化:
(2) 在測試用例中的前置動做,添加獲取庫存上限未賣光團單
。
這樣就能夠在整個測試用例中,使用${pre.ProductID}
,來替換掉原有的數據信息。
(3) 最後請求接口,返回了執行成功 。
Q & A
Q:那若是一樣是獲取三個參數,使用3個「參數化的Select操做」和使用1個「前置動做的Select操做」又有什麼不一樣呢?
A: 不一樣在於執行時間上。
好比,咱們查詢最新的有效團單的「單號」「下單人」和「手機號」三個字段。
使用3個「參數化的Select操做」:可能當執行${單號}的時候獲得的訂單號是「10001」,可是當執行到${下單人}的時候,可能有誰又下了一單,可能取到的下單人變成了「10002」的「李四」而不是「10001」的「張三」了,最後可能「單號」「下單人」和「手機號」三個字段去的數據並不是同一行的數據。
而使用「前置動做的Select操做」:就能夠避免上面的問題,由於全部字段的數據是一次性查詢出來的,就不會出現錯位的狀況。
Q : 那「參數化的Select操做」和「前置動做的Select操做」這樣不一樣的取值時機又有什麼好用之處呢?
A : 因爲「前置動做」必定是接口請求前執行,「參數化」必定是用到的時候才執行這樣的特性。
因此在檢查點中,若是要驗證一個數據庫字段在通過接口調用後發生了變動,那使用「前置動做」和「參數化」同時去查詢這個字段,而後進行比較,不一致就說明發生了變化。
因此根據使用場景,選擇合適的參數化方式,很重要,選擇對了,能大大提高測試用例的測試數據健壯性。
3.5 執行各部分
回到一開始的流程圖,能夠按照一類一類來看執行過程。
測試發起
測試發起基本仍是使用的Jenkins,穩定、成熟、簡單、公司工具組支持,也支持從Lego的Web頁面進行執行操做。
數據 / 環境準備
使用 @DataProvider 的方式,從DB數據庫中讀取測試用例,逐一執行進行測試。
測試執行
在正式執行測試用例以前,會先進行一波參數替換的動做,在調用接口以後,還會執行一次參數替換動做。
參數替換後會進行前置動做的執行,而後在調用接口以後還會執行測試後動做,最後執行後置動做。
接口請求這部分就沒什麼好說的了,就是經過接口請求的參數,請求對應的接口,拿到返回結果。
這裏的話是爲了方便通用,因此要求返回的結果都是使用的String類型。這樣作最大的好處就是。好比說我如今有一種新的接口類型須要接入。那隻須要寫一個方法可以請求到這個接口,而且拿到String類型的返回結果,就能夠很快將新的接口類型接入Lego測試平臺進行接口測試。
檢查點校驗
檢查點部分是一條自動化測試用例的精髓,一條自動化測試用例是否能真正的發揮它的測試功能,就是看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}
這樣的檢查點:
「參數化」和「先後置動做」也支持遞歸配置,這些都是爲了可以讓接口自動化測試用例寫的更加靈活好用。
測試結果
使用ReportNG能夠打印出很漂亮的報告。
報告會自定義一些高亮等展現方式,只須要在ReportNG使用前加上下面的語句,就能夠支持「輸出逃逸」,可以使用HTML標籤自定義輸出樣式。
System.setProperty("org.uncommons.reportng.escape-output", "false");
後期優化
當使用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 總體組成
目前Lego由五個不一樣的項目組成,分別是「測試腳本」、「Lego-web頁面項目」、「用於執行接口測試的base包」、「小工具集合Lego-kit」和「lego-job」,經過上圖能夠看出各項目間的依賴關係。
細化各個項目的功能,就是下圖:
簡單來講,網站部分和腳本是分離的,中間的紐帶是數據庫。因此,沒有網站,腳本執行一點問題也沒有;一樣的,網站的操做,和腳本也沒有關係。
4.3 使用-平常維護
Step 1
天天上班來會收到這樣的測試郵件,經過郵件能知道昨晚執行的狀況。若是有報錯,能夠點擊「詳細報告連接」,跳轉到在線報告。
Step 2
在現報告能夠直接看到執行報錯的信息,而後點擊「LEGO維護傳送門」,能夠跳轉到Lego站點上,進行用例維護。
Step 3
跳轉到站點上之後,能夠直接展現出該條測試用例的全部信息。定位,維護、保存,維護用例,能夠點擊「執行」查看維護後的執行結果,維護好後「保存」便可。
僅僅3步,1~2分鐘便可完成對一條執行失敗的用例進行定位、調試和維護動做。
4.4 用例編輯
經過頁面,咱們就能夠對一條測試用例進行:
- 新建
- 複製
- 編輯
- 刪除
- 是否放入每日構建中進行測試
4.5 在線調試
lego-web項目一樣的使用base進行的用例執行,因此執行結果和打印都與腳本執行的一致的。
4.6 用例生成工具
爲了更方便的寫用例,針對部分接口開發了一鍵批量生成用例的小工具。
4.7 執行結果分析
經過Jenkins接口、Base包中基礎Test方法,將結果收集到數據庫,便於各組對測試結果進行分析。
這是天天執行後成功率走勢圖:
也能夠按月進行統計,生成統計的圖表,幫助各個團隊進行月報數據收集和統計。
4.8 失敗緣由跟蹤
有了能直觀看到測試結果的圖表,就會想要跟蹤失敗緣由。
因此在成功率數據的右邊,會有這樣的跟蹤失敗緣由的入口,也能夠很直觀地看到哪一些失敗的緣由尚未被跟蹤。點開後能夠對失敗緣由進行記錄。
最後會有生成圖表,能夠很清晰地看到失敗緣由以及失敗類型的佔比。
4.9 代碼覆蓋率分析
結合Jacoco,咱們能夠對接口自動化的代碼覆蓋率進行分析。
在多臺Slave機器上配置Jacoco仍是比較複雜的,因此能夠開發覆蓋率配置輔助工具來幫助測試同窗,提升效率。
4.10 用例優化方向
除了上面的圖表,還會給用例優化提供方向。
經過用例數量統計的圖表,咱們能夠知道哪些服務用例還比較少,哪些環境的用例還比較少,能夠比較有針對性的進行測試用例的補充。
經過失敗緣由的圖表,咱們能夠改善本身用例中的「參數化」和「先後置動做」的使用,增長測試用例的健壯性。
經過線上接口調用量排序的圖表。咱們能夠有效的知道優先維護哪些服務的測試用例,經過表格中,咱們能夠看到,哪些服務已經覆蓋了測試用例,哪些沒有被覆蓋, 給各組的QA制定用例開發計劃,提供參考。
同時在維護接口自動化測試的時候,都會看到用例評分的狀況,來協助QA提升用例編寫的質量。
4.11 收集反饋/學習
還作了「需求白板」,用來收集使用者的需求和Bug。除此以外,Lego平臺已經不僅是一個接口測試的平臺,還可讓想學習開發的QA領任務,學習一些開發技巧,提升本身的代碼能力。
5、總結
- 爲了減小開發成本,使用比較常見的Jenkins+TestNG的腳本形式。
- 爲了簡化code操做,使用DB進行測試用例存儲,並抽象出用例摸版。
- 爲了減低新建用例成本,開發「用例維護頁面」和「一鍵生成」等工具。
- 爲了減低維護成本,加跳轉連接,維護一條用例成本在幾分鐘內。
- 爲了增長用例健壯性,設計了「參數化」、「先後置動做」等靈活的參數替換。
- 爲了易用和兼容,統一「返回結果」類型,統一「檢查點」的使用。
- 爲了接口自動化用例設計提供方向,結合Jacoco作代碼覆蓋率統計,並開發相關配置工具
- 爲了便於分析數據,從DOM、CAT、Jenkins上爬各類數據,在頁面上用圖表展現。
- 爲了優化用例,提供「用例打分」、「線上調用量排行」等數據進行輔助。