測試篇

Lego-美團接口自動化測試實踐 
智能支付穩定性測試實戰
大衆點評App的短視頻耗電量優化實戰
「小衆」之美——Ruby在QA自動化中的應用
美團點評雲真機平臺實踐 
質量運營在智能支付業務測試中的初步實踐html

Lego-美團接口自動化測試實踐

1、概述

1.1 接口自動化概述

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

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

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

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

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

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

1.2 提升ROI

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

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

針對「減小投入成本」

咱們須要作到:ios

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

針對「增長使用率」

咱們須要作到:git

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

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

首頁

首頁

 

用例維護頁面

用例維護頁面

 

自動化用例列表

自動化用例列表

 

在線執行結果

在線執行結果

 

用例數量統計

用例數量統計

 

1.3 Lego的組成

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

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

2、腳本設計

2.1 Lego的作法

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

Jenkins+TestNG的結構

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條用例進行逐一測試。

<test>標籤時,能夠分組展現

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

報告更美觀豐富

因爲使用了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、總結

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

 

 

智能支付穩定性測試實戰

 

本文根據美團高級測試開發工程師勳偉在美團第43期技術沙龍「美團金融千萬級交易系統質量保障之路」的演講整理而成。主要介紹了美團智能支付業務在穩定性方向遇到的挑戰,並重點介紹QA在穩定性測試中的一些方法與實踐。

背景

美團支付承載了美團所有的交易流量,按照使用場景能夠將其分爲線上支付和智能支付兩類業務。線上支付,支撐用戶線上消費場景,處理美團全部線上交易,爲團購、外賣、酒店旅遊等業務線提供支付能力;智能支付,支撐用戶到店消費場景,處理美團全部線下交易,經過智能POS、二維碼支付、盒子支付等方式,爲商家提供高效、智能化的收銀解決方案。其中,智能支付做爲新擴展的業務場景,去年也成爲了美團增速最快的業務之一。

面臨的挑戰

而隨着業務的快速增加,看似簡單的支付動做,背後系統的複雜度卻在持續提高。體如今:上層業務入口、底層支付渠道的不斷豐富,微服務化背景下系統的縱向分層、服務的橫向拆分,還有對外部系統(營銷中心、會員中心、風控中心等)、內部基礎設施(隊列、緩存等)的依賴也愈來愈多,整條鏈路上的核心服務節點超過20個,業務複雜度可想而知。

此外,技術團隊在短期內就完成了從幾我的到近百人規模的擴張,這也是一個潛在的不穩定因素。曾經在一段時間內,整個系統處在「牽一髮而動全身」的狀態,即便自身系統不作任何發版升級,也會由於一些基礎設施、上下游服務的問題,業務會毫無徵兆地受到影響。

痛定思痛,咱們對發生過的線上問題進行復盤,分析影響服務穩定性的緣由。經過數據發現,72%的嚴重故障集中在第三方服務和基礎設施故障,對應的一些典型事故場景,好比:第三方支付通道不穩定、基礎設施(如消息隊列)不穩定,進而致使整個系統雪崩,當依賴方故障恢復後,咱們的業務卻很難當即恢復。

解決方案

基於這些問題,咱們開展了穩定性建設專項,目的很明確:提高服務的可用性。目標是逐步將系統可用性從2個9提高到3個9,再向4個9去努力。這個過程當中最核心的兩個策略:柔性可用,意思是儘量保證核心功能可用,或在有損狀況下儘量保證核心用戶體驗,下降影響;另外一個是快速恢復,即用工具或機制保證故障的快速定位和解決,下降故障修復時間。

圍繞這兩個策略,在穩定性建設中的常見操做:限流、熔斷降級、擴容,用於打造系統的柔性可用;故障響應SOP、故障自動處理,用於故障處理時的快速恢復。而QA的工做更側重於對這些「常見操做」進行有效性驗證。基於經驗,重點介紹「三把利劍」:故障演練、線上壓測、持續運營體系。

故障演練的由來

舉個真實的案例,在一次處理某支付通道不穩定的線上問題時,開發同窗執行以前已經測試經過的預案(服務端關閉該通道,預期客戶端將該支付通道的開關置灰,並會提示用戶使用其餘支付方式),但執行中卻發現預案沒法生效(服務端操做後,客戶端該支付通道仍處於開啓狀態)。非故障場景下預案功能正常,故障場景下卻失效了。

這就是故障演練的由來,咱們須要儘量還原故障場景,才能真正驗證預案的有效性。

故障演練的總體方案

故障演練的總體方案,主要分爲三部分:

  • 負載生成模塊,負責儘量還原系統的真實運行場景(要求覆蓋核心業務流程)。
  • 故障注入模塊,包含故障注入工具、故障樣本庫(涵蓋外部服務、基礎組件、機房、網絡等各類依賴,並重點關注超時、異常兩種狀況)。
  • 業務驗證模塊,結合自動化測試用例和各個監控大盤來進行。

爲了更高效地開展故障演練,咱們的策略是分爲兩個階段進行。首先,針對單系統進行故障演練,從故障樣本庫出發,全面覆蓋該系統全部的保護預案;在此基礎上,進行全鏈路故障演練,聚焦核心服務故障,驗證上下游服務的容錯性。

故障演練的效果

事實證實,故障演練確實給咱們帶來了不少「驚喜」,暴露了不少隱患。這裏列舉三類問題:數據庫主從延遲影響交易;基礎設施故障時,業務未作降級;依賴服務超時設置不合理、限流策略考慮不足等。

線上壓測的由來

面對業務的指數級增加,咱們必須對系統可承載的流量作到心中有數。對於QA來講,須要找到精準、高效的系統容量評估方法。咱們碰到的難點包括:鏈路長、環節多、服務錯綜複雜,線下環境與線上差別大等等,基於測試有效性和測試成本考慮,咱們決定要作線上壓測,並且要實現全鏈路的線上壓測。

線上壓測的總體方案

全鏈路壓測的實現方案,與業界主流方案沒有太大區別。根據壓測流程,首先,場景建模,以便更真實的還原線上系統運行場景;其次,基礎數據構造,應知足數據類型以及量級的要求,避免數據熱點;以後,流量構建,讀寫流量構造或回放,同時對壓測流量進行標記和脫敏;再以後,壓測執行,過程當中收集鏈路各節點的業務運行狀態、資源使用狀況等;最後,生成壓測報告。

基於全鏈路線上壓測方案,能夠根據業務需求,靈活地進行單鏈路壓測、分層壓測等。更爲重要的是,基於壓測咱們能夠進行線上的故障演練,用於更加真實的驗證系統限流、熔斷等保護預案。

線上壓測的效果

經過全鏈路線上壓測,一方面讓咱們對系統容量作到心中有數,另外一方面也讓咱們發現了線上系統運行過程當中的潛在問題,並且這些問題通常都是高風險的。一樣列舉三類問題:基礎設施優化,如機房負載不均衡、數據庫主從延遲嚴重等;系統服務優化,如線程池配置不合理、數據庫須要拆分等;故障預案優化,如限流閾值設置太低,有的甚至已經接近限流邊緣而渾然不知等等。

持續運營體系的由來

智能支付的穩定性建設是做爲一個專項在作,持續了近3個月的時間;在效果還不錯的狀況下,咱們從智能支付延伸到整個金融服務平臺,以虛擬項目組的方式再次運轉了3個月的時間。經過項目方式,確實能集中解決現存的大部分穩定性問題,但業務在發展、系統在迭代,穩定性建設必然是一項長期的工做。因而,QA牽頭SRE、DBA、RD,創建了初步的穩定性持續運營體系,並在持續完善。

持續運營體系的總體方案

下面介紹持續運營體系的三大策略:

流程規範工具化,儘量減小人爲意識因素,下降人力溝通和維護成本。

如:配置變動流程,將配置變動視同代碼上線,以PR方式提交評審;代碼規範檢查落地到工具,儘量將編碼最佳實踐抽取爲規則,將人工檢查演變爲工具檢查。

質量度量可視化,提取指標、經過數據驅動相關問題的PDCA閉環。

如:咱們與SRE、DBA進行合做,將線上系統運維中與穩定性相關的指標提取出來,相似數據庫慢查詢次數、核心服務接口響應時長等等,並對指標數據進行實時監控,進而推動相關問題的解決。

演練壓測常態化,下降演練和壓測成本,具有常態化執行的能力。

如:經過自動化的觸發演練報警,驗證應急SOP在各團隊實際執行中的效果。

基於以上三個策略,構建穩定性持續運營體系。強調閉環,從質量度量與評價、到問題分析與解決,最終完成方法與工具的沉澱;過程當中,經過平臺建設來落地運營數據、完善運營工具,提高運營效率。

持續運營體系的效果

簡單展現當前持續運營體系的運行效果,包含風險評估、質量大盤、問題跟進以及最佳實踐的沉澱等。

將來規劃

綜上即是智能支付QA在穩定性建設中的重點工做。對於將來工做的想法,主要有3個方向。第一,測試有效性提高,持續去擴展故障樣本庫、優化演練工具和壓測方案;第二,持續的平臺化建設,實現操做平臺化、數據平臺化;第三,智能化,逐步從人工運營、自動化運營到嘗試智能化運營。

 

 

大衆點評App的短視頻耗電量優化實戰

前言

美團測試團隊負責App的質量保證工做,平常除了App的功能測試之外,還會重點關注App的性能測試。如今你們對手機愈來愈依賴,而上面各App的耗電量,直接影響了手機的待機時間,是用戶很是關心的一點。本文主要經過一個典型案例,介紹App性能測試中的電量測試,並總結了咱們由此引起的一些思考。

1、案例分析

短視頻做爲已被市場驗證的新內容傳播載體,能有效增長用戶停留時長。大衆點評App從9.3版本開始推出短視頻相關內容,在各頁面新增了短視頻模塊。在短視頻功能測試中,咱們發現若是在視頻列表頁中播放視頻,手機很快就會發燙。針對這種現象,咱們立刻拉取數據進行了分析,測試數據代表,視頻列表頁耗電量居然是詳情頁的11倍。這是怎麼回事兒呢?

目前行業內有不少電量測試的方法,咱們採用的是Battery Historian,這是Google推出的一款Android系統電量分析工具,支持5.0(API 21)及以上系統手機的電量分析。

1. 測試對象

短視頻主要包括三個核心頁面:視頻列表頁、視頻詳情頁、做者頁,本次的測試對象就是這三個頁面。

2. 測試過程

測試機型:華爲Mate 9 Android 7.0 電池容量:4000mAh
播放的視頻時長:1min15s 測試場景設計:WiFi環境下,打開App,播放視頻,經過點擊「從新播放」,連續播放10次 對比場景:停在App首頁20min,手機不滅屏 注意:測試過程不充電,每次測試環境一致

3. 測試結果

以下是Battery Historian測試結果部分截圖:

視頻列表頁

視頻列表頁

 

視頻詳情頁

視頻詳情頁

 

對測試結果數據進行彙總整理:

消耗電量:系統總電量的佔比

從測試結果能夠看到,短視頻列表頁耗電量特別高,是視頻詳情頁的11倍。

4. 問題定位

視頻列表頁消耗電量太高,從測試數據能夠很明顯的看出來,視頻列表頁CPU佔用時間高不少。從播放器佈局來看,列表頁和做者頁比視頻詳情頁只是多出了動畫音符。以下圖,紅框中圈出的視頻左下角的音符。

電量消耗差別這麼大,是否跟動畫音符有關呢。爲了排除這個問題,從新編譯了一個去掉動畫音符的APK進行測試。測試結果:

從測試結果來看,CPU和耗電量很明顯都降低了不少,所以肯定是動畫音符引發的。打開GPU視圖更新的開關,查看三個頁面的繪製狀況。打開視頻列表頁,能夠看到,動畫音符每波動一次,會致使整個頁面都在不停的繪製。以下是視頻列表頁繪製的狀況:

從動圖能夠很明顯看出該頁面繪製十分異常,動畫音符每波動一次,會致使整個頁面都從新繪製一遍。

因此,到這裏就明白了問題的緣由,由於頁面上動畫音符的實現方式有問題,動畫音符波動時,致使整個頁面會跟着一塊兒不停的從新繪製。而頁面的重複繪製,會使App CPU佔用比正常狀況下高出不少,進而致使耗電量高。

5. 修復後驗證

定位到緣由以後,開發針對性的進行了修復。動畫音符柱狀圖的實現,以前設計由多個可變化的單柱形View組成,單個柱形View重寫了onMeasure & OnDraw方法,從外部柱狀圖View中初始化單個柱子的高度,而後自動根據一個函數式來變化高度。由於每次都須要層層調用Measure和對應的Layout,因此形成外層控件的屢次layout,進而形成CPU佔用率增大。修復以後,使用另外一種方式實現,只重寫了View的OnDraw方法,每次使用Canvas畫出全部柱狀圖,使用ValueAnimator來計算變化柱狀圖高度,也再也不影響父控件的Layout。以下是修復先後的核心代碼:

修復以後動畫音符波動時的繪製區域:

修復以後,從新使用Battery Historian進行驗證,測試結果:

從上面的測試結果,能夠看到,視頻列表頁和做者頁,耗電狀況獲得明顯的優化。

總結一下,短視頻耗電量的問題,是因爲錯誤的繪製方法,致使CPU佔用太高,進而致使耗電量高。那麼由於動畫音符致使耗電量異常的問題到這裏就完美的解決了。CPU負載高,會致使耗電量高是顯而易見的。可是還想深刻探索一下,在手機系統各App耗電量排行榜中,耗電量是怎麼計算的?還有哪些因素會影響耗電量呢?帶着這些疑問,咱們來看看系統計算耗電量的原理。

2、耗電量計算原理

根據物理學中的知識,功=電壓*電流*時間,可是一部手機中,電壓值U正常來講是不會變的,因此能夠忽略,只經過電流和時間就能夠表示電量。模塊電量(mAh)=模塊電流(mA)*模塊耗時(h)。模塊耗時比較容易理解,可是模塊電流怎樣獲取呢,不一樣廠商的手機,硬件不一樣,是否會影響模塊的電流呢。看一下系統提供的接口:./frameworks/base/core/java/com/Android/internal/os/PowerProfile.java

該類提供了public double getAveragePower(String type)接口,type可取PowerProfile中定義的常量值,包括POWER_CPU_IDLE(CPU空閒時),POWER_CPU_ACTIVE(CPU處於活動時),POWER_WIFI_ON(WiFi開啓時)等各類狀態。而且從接口能夠看出來,每一個模塊的電流值,是從power_profile.xml文件取的值。PowerProfile.java只是用於讀取power_profile.xml的接口而已,後者纔是存儲系統耗電信息的核心文件。power_profile.xml文件的存放路徑是/system/framework/framework-res.apk。

以Nexus 6P爲例,在該路徑獲取到framework-res.apk文件。使用apktool,對framework-res.apk進行反解析,獲取到手機裏面的power_profile.xml文件,內容以下所示:

<?xml version="1.0" encoding="utf-8"?> <device name="Android"> <item name="none">0</item> <item name="screen.on">169.4278765</item> <item name="screen.full">79.09344216</item> <item name="bluetooth.active">25.2</item> <item name="bluetooth.on">1.7</item> <item name="wifi.on">21.21733311</item> <item name="wifi.active">98.04989804</item> <item name="wifi.scan">129.8951166</item> <item name="dsp.audio">26.5</item> <item name="dsp.video">242.0</item> <item name="gps.on">5.661105191</item> <item name="radio.active">64.8918361</item> <item name="radio.scanning">19.13559783</item> <array name="radio.on"> <value>17.52231575</value> <value>5.902211798</value> <value>6.454893079</value> <value>6.771166916</value> <value>6.725541238</value> </array> <array name="cpu.speeds.cluster0"> <value>384000</value> <value>460800</value> <value>600000</value> <value>672000</value> <value>768000</value> <value>864000</value> <value>960000</value> <value>1248000</value> <value>1344000</value> <value>1478400</value> <value>1555200</value> </array> <arrayname="cpu.speeds.cluster1"> <value>384000</value> <value>480000</value> <value>633600</value> <value>768000</value> <value>864000</value> <value>960000</value> <value>1248000</value> <value>1344000</value> <value>1440000</value> <value>1536000</value> <value>1632000</value> <value>1728000</value> <value>1824000</value> <value>1958400</value> </array> <itemname="cpu.idle">0.144925583</item> <itemname="cpu.awake">9.488210416</item> <arrayname="cpu.active.cluster0"> <value>202.17</value> <value>211.34</value> <value>224.22</value> <value>238.72</value> <value>251.89</value> <value>263.07</value> <value>276.33</value> <value>314.40</value> <value>328.12</value> <value>369.63</value> <value>391.05</value> </array> <arrayname="cpu.active.cluster1"> <value>354.95</value> <value>387.15</value> <value>442.86</value> <value>510.20</value> <value>582.65</value> <value>631.99</value> <value>812.02</value> <value>858.84</value> <value>943.23</value> <value>992.45</value> <value>1086.32</value> <value>1151.96</value> <value>1253.80</value> <value>1397.67</value> </array> <arrayname="cpu.clusters.cores"> <value>4</value> <value>4</value> </array> <itemname="battery.capacity">3450</item> <arrayname="wifi.batchedscan"> <value>.0003</value> <value>.003</value> <value>.03</value> <value>.3</value> <value>3</value> </array> </device> 

從文件內容中能夠看到,power_profile.xml文件中,定義了消耗電量的各模塊。以下圖所示:

文件中定義了該手機各耗電模塊在不一樣狀態下的電流值。剛剛提到,電量只跟電流值和時間相關,因此經過這個文件,再加上模塊的耗時,就能夠計算出App消耗的電量,App電量=∑App模塊電量。劃重點,手機系統裏面的電量排行,也是根據這個原理計算的。

瞭解原理對於日常在App耗電量的測試有很大的幫助。由於獲取到手機power_profile.xml文件,就能夠清楚的知道這個手機上,哪些模塊會耗電,以及哪些模塊在什麼狀態下耗電量最高。那麼測試的時候,應該重點關注調用了這些模塊的地方。好比App在哪些地方使用WiFi、藍牙、GPS等等。

例如最近對比測試其餘App發現,在一些特定的場景下,該App置於前臺20min內,掃描了WiFi 50次,這種異常會致使App耗電量大大增長。而且反過來,當有case報App耗電量異常時,也能夠從這些點去考慮,幫助定位問題。

3、電量測試方法總結

如上,列出的一些經常使用的電量測試方法。綜合各方法的優缺點,在定製個性化電量測試工具以前,目前採用的方法是Battery Historian。目前行業內,App耗電測試有不少種方案,若是僅僅測試出一個總體的電量值,對於定位問題是遠遠不夠的。藉助Battery Historian,能夠查看自設備上次充滿電以來各類彙總統計信息,而且能夠選擇一個App查看詳細信息。因此QA的測試結果反饋從「這個版本App耗電量」高,變成「這個版本CPU佔用高」「這個版本WiFi掃描異常」,能夠幫助更快的定位到問題緣由及解決問題。

固然,除了測試方法和測試工具,測試場景設計也很是重要。若是是在App內毫無規律的瀏覽,即便發現頁面有問題,有很難定位到是哪一個模塊的問題。因此要針對性的設計場景,而且進行一些場景的對比,找出差別的地方。

4、總結

本文主要經過一個案例,介紹關於App電量測試中使用的一些基本方法和思路。電量測試採用的Battery Historian方法,雖然能初步解決問題,可是在實際的應用場景中還存在不少不足。目前美團雲測平臺,已經集成了電量測試方法,經過自動化操做,獲取電量測試文件並進行解析,極大的提升了測試效率。目前每一個版本發佈以前,咱們都會進行專門的電量測試,保障用戶的使用體驗。在電量測試方面,美團測試團隊還在持續的實踐和優化中。

 

「小衆」之美——Ruby在QA自動化中的應用

前言

關於測試領域的自動化,已有不少的文章作過介紹,「黑科技」也比比皆是,如經過Java字節碼技術實現接口的錄製,Fiddler錄製內容轉Python腳本,App中的插樁調試等,可見角度不一樣,對最佳實踐的理解也不同。這裏想要闡述的是,外賣(上海)QA團隊應用相對「小衆」的Ruby,在資源有限的條件下實現自動化測試的一些實踐與經驗分享。

背景

加入外賣上海團隊時,共2名QA同窗,分別負責App與M站的功能測試,自動化測試停留在學習北京側接口測試框架的階段,實效上近乎爲0,能力結構上在代碼這部分是明顯薄弱的。而擺在面前的問題是,迴歸測試的工做量較大,特別是M站渠道衆多(4個渠道),移動端API的接口測試需區分多個版本,自動化測試的開展勢在必行。在這樣的條件下,如何快速且有效地搭建並推廣自動化測試體系?在過去對自動化測試的多種嘗試及實踐的總結後,選擇了Ruby。

Why Ruby?

簡單點說就是:並不聰明的大腦加上「好逸惡勞」的思想,促使我在這些年的自動化測試實踐中,不斷尋找更合適的解決方案。所謂技術,其本質都是站在別人的肩膀上,肩膀的高度也決定了實現目標的快慢,而Ruby正符合所需的一些特徵:

  1. 效率。自身應該算是「純粹」的測試人員,在「測試開發」這重職業並不普及的年代,一直但願有種語言可讓測試的開發效率超過研發,Ruby作到了;
  2. 人性化的語法,各類糖。相似1.day.ago,簡單的表達不須要解釋;
  3. 強大的元編程能力。基於此,DHH放棄了PHP而使用Ruby開發出了Rails,DSL也所以成爲Ruby開發的框架中很是普通的特性,而這對於不少主流語言都是種奢望;
  4. 對於測試來講足夠充足的社區資源。不涉及科學計算,不涉及服務開發,在沒有這些需求的狀況下,Python和Java再也不是必需。

脫離了開發語言的平臺,但在不關注白盒測試的狀況下並沒有太多不妥。當Ruby用於測試開發,基本「屏蔽」了性能上的劣勢,充分展示了敏捷、易用的特色,也是選擇這一技術路線的主要因素。

接口自動化框架Coral-API

框架思路

接口自動化測試方案衆多,我的認爲它們都有本身的適用的範圍和優缺點。UI類工具雖輕鬆實現無碼Case,但在處理接口變更和全鏈路接口流程上多少會顯得有些繁瑣(尤爲在支持數據驅動需求下),過多的規則、變量設置和編碼也相差無幾;錄製類型的方案,更多仍是適合迴歸,對於較全面的接口測試也須要必定的開發量。基於這些權衡考慮,採用一種編碼儘量少、應用面更廣的接口自動化框架實現方式,把它命名爲Coral-API,主要有如下特色:

  1. 測試數據處理獨立

    • 預先生成測試所需的最終數據,區分單接口測試數據(單接口數據驅動測試)與鏈路測試數據
    • 經過命令行形式的語句解決了參數的多層嵌套及動態數據生成的問題
    • Excel中維護測試數據,最終轉化爲YML或存入DB,折中解決了JSON形式的數據難維護問題
  2. 學習成本低

    • 框架提供生成通用結構代碼的功能,使測試人員更關注於業務邏輯處理
    • DSL的書寫風格,即使沒有Ruby的語言基礎,也能夠較快掌握基本的接口測試用例編寫
  3. 擴展性

    • 支持Java平臺的擴展
    • 支持HTTP/RPC接口,可根據開發框架擴展
    • 框架基於Rspec,支持多種驗證方式(Build-In Matcher),及支持自定義Matcher,目前實現了JSON去噪的Diff,各類複合的條件比較

以單個接口測試編寫爲例,下圖描述了具體流程:

coral-api框架

coral-api框架

 

從圖中能夠看到,安裝了Coral-API的gem後,可經過命令行 「coral g {apiname}」 ,經過模板來生成測試數據XLS及對應的數據處理文件(例如ApiOne.rb文件),修改並執行ApiOne.rb文件,則能夠生成最終的測試數據(YML文件)及測試類和Case文件。若是開發框架支持(有途徑可解析出參數),則能夠經過腳本直接生成整個服務下全部接口的測試代碼,實現自動化Case的同步開發。這種處理過程主要是一併解決了如下幾個問題:

  1. 複雜結構的測試數據構造
  2. 動態參數的賦值
  3. 測試數據的維護
  4. 測試數據的加載

假設有如下這樣一個接口請求格式,包含一個orderInfo的子節點,及payInfo的list,還須要解決一些變化值的問題,如各類id和time(暫且稱爲動態字段)。通常框架中會以JSON格式來做爲測試用例的請求格式,在代碼中按變量處理動態字段值。JSON做爲請求數據的保存形式,存在一個很大的問題,就是後期維護,尤爲是Case數量較多的時候。所以,考慮仍以Excel爲數據維護的初始形式(使用上更直觀),經過Sheet的嵌套來處理複雜結構,也便於後期接口參數變更後的Case維護。

userId: E000001 requestId: '1938670097' orderInfo: orderId: '6778043386' count: '2' name: testgoods payInfo: - transactionId: '510455433082284' payTime: '2017-04-04 13:03:34' payType: BOC - transactionId: '167338836018587' payTime: '2017-04-04 13:03:34' payType: Wallet createTime: '2017-04-04 13:03:34' 

測試數據的Excel作以下設計,Main中爲第一層參數結構,預期響應另分一個Sheet,子節點和list節點的內容寫在對應的Sheet中,動態值均置爲空,在接口數據類中處理,orderInfo節點和payInfo節點均另寫在新的Sheet中,用於單接口數據驅動的Case與鏈路迴歸用Case分開,固然這會增長一些Case維護的成本,能夠選擇是否區分。

示例的數據結構,經過如下語句便可實現,若是須要爲後續接口測試提供前置步驟的數據,也能夠同步實現,下例中爲後續接口生成了5條請求數據。針對接口參數變更的狀況,能夠修改Excel和數據處理類文件,執行一遍便可,也提供了批量從新生成全部接口數據的腳本。

class Demo < ApiCaseBase update self.request,:requestId=>'gen_randcode(10)',:createTime=>'get_datetime' add_node self.request,"orderInfo",:orderId=>'gen_randcode(10)' add_list self.request,"payInfo",:transactionId=>'gen_randcode(15)',:payTime=>'get_datetime' sheetData={'ForApiOther'=>5} generate_data self,sheetData do update_force @data,:orderId=>'gen_randcode(10)',:createTime=>'get_datetime' add_node_force @data,"orderInfo",:orderId=>'gen_randcode(10)' add_list_force @data,"payInfo",:transactionId=>'gen_randcode(15)',:payTime=>'get_datetime' end end 

Excel做爲Case的維護形式,缺點是Case較多狀況下頻繁讀取比較影響時間。在這種狀況下,考慮到把數據序列化到YML中,啓動執行時接口測試類自動與測試數據進行綁定。在Case中能夠直接使用形如 DemoTest.request[1]的請求數據,提升了速度,結構上也清晰了很多。

接口測試類文件(HTTP接口調用爲例)生成的模板以下,修改對應的接口信息便可,支持DB驗證(代碼塊p這部分是目前惟一須要寫Ruby代碼的地方,固然這是非必需項)。

require 'apicasebase' class PreviewTest include ApiTestBase set_cookie set_domain "Domain_takeaway" set_port 80 set_path "/waimai/ajax/wxwallet/Preview" set_method "get" set_sql "select * from table" p = proc do |dbres| ## do something ## return a hash end set_p p end 

TestCase文件以下,原則上無需修改,只須要在測試數據的Excel中編寫匹配規則及預期輸出,基本上實現了單個接口無編碼的數據驅動測試。

require 'Preview_validate' RSpec.shared_examples "Preview Example" do |key,requestData,expData| it 'CaseNo'+ key.to_s + ': '+expData['memo'] do response = PreviewTest.response_of(key) expect(response).to eval("#{expData['matcher']} '#{expData['expection']}'") end end RSpec.describe "Preview接口測試",:project=>'api_m_auto',:author=>'Neil' do PreviewTest.request.each{|key,parameter|include_examples "Preview Example",key,PreviewTest.request[key],PreviewTest.expect[key]} end 

接口流程Case編寫就是各獨立接口的業務邏輯串聯,重點是Case的組織,把一些公用的Steps獨立出shared_examples,在主流程的Case中include這些shared_examples便可,關聯的上下游參數 經過全局變量來傳遞。

RSpec.describe "業務流程測試" ,:project=>'api_m_auto',:author =>'Neil' do let(:wm_b_client) { WmBClient.new('自配') } before(:context) do init_step end context "在線支付->商家接單->確認收貨->評價" do include_examples "OrderAndPay Example",1 include_examples "AcceptOrder Example" include_examples "CommentStep Example" end end 

經過上面的介紹,能夠看到,Case的編寫大部分能夠經過代碼生成實現(熟悉之後部分接口也能夠根據須要進行操做步驟的取捨,如直接編寫YML)。實踐下來的狀況是,從各方面一無全部,17我的日左右的時間,完成了M站API層接口自動化(業務流程9個,單個接口10個)及點評外賣移動端API的接口自動化(業務流程9個,單個接口20個),實現了外賣業務全鏈路接口迴歸,平均每一個業務流Case步驟9個左右。期間也培養了一名以前未接觸過Ruby的同窗,在完成了初版開發後,兩名初級階段的同窗逐步承擔起了框架的改進工做,實現了更多有效的驗證Matcher,並支持了移動端API多版本的測試。以後的迴歸測試不只時間上縮減了50%以上,也經過接口自動化3次發現了問題,其中一次API不一樣版本致使的Bug充分體現了自動化測試的效率。經過ci_reporter,能夠方便地將Rspec的報告格式轉爲JUnit的XML格式,在Jenkins中作對應的展現。

測試報告jenkins展現

測試報告jenkins展現

 

解決接口多版本測試的例子

移動端API自動化中存在的問題就是,一個接口會存在多個版本並存的狀況,有header中內容不一樣的,或formdata內容不一樣的狀況,在接口迴歸中必須都要照顧到,在Coral-API中咱們採用如下方式進行處理。

在config.yml中定義各版本的header。

Domain_takeaway_header: v926: '{"connection":"upgrade","x-forwarded-for":"172.24.121.32, 203.76.219.234","mkunionid":"-113876624192351423","pragma-apptype":"com.dianping.ba.dpscope","mktunneltype":"tcp","pragma-dpid":"-113876624192351423","pragma-token":"e7c10bf505535bfddeba94f5c050550adbd9855686816f58f0b5ca08eed6acc6","user-agent":"MApi 1.1 (dpscope 9.4.0 appstore; iPhone 10.0.1 iPhone9,1; a0d0)","pragma-device":"598f7d44120d0bf9eb7cf1d9774d3ac43faed266","pragma-os":"MApi 1.1 (dpscope 9.2.6 appstore; iPhone 10.0.1 iPhone9,1; a0d0)","mkscheme":"https","x-forwarded-for-port":"60779","X-CAT-TRACE-MODE":"true","network-type":"wifi","x-real-ip":"203.76.219.234","pragma-newtoken":"e7c10bf505535bfddeba94f5c050550adbd9855686816f58f0b5ca08eed6acc6","pragma-appid":"351091731","mkoriginhost":"mobile.dianping.com","pragma-unionid":"91d9c0e21aca4170bf97ab897e5151ae0000000000040786871"}' v930: '{"connection":"upgrade","x-forwarded-for":"172.24.121.32, 203.76.219.234","mkunionid":"-113876624192351423","pragma-apptype":"com.dianping.ba.dpscope","mktunneltype":"tcp","pragma-dpid":"-113876624192351423","pragma-token":"e7c10bf505535bfddeba94f5c050550adbd9855686816f58f0b5ca08eed6acc6","user-agent":"MApi 1.1 (dpscope 9.4.0 appstore; iPhone 10.0.1 iPhone9,1; a0d0)","pragma-device":"598f7d44120d0bf9eb7cf1d9774d3ac43faed266","pragma-os":"MApi 1.1 (dpscope 9.3.0 appstore; iPhone 10.0.1 iPhone9,1; a0d0)","mkscheme":"https","x-forwarded-for-port":"60779","X-CAT-TRACE-MODE":"true","network-type":"wifi","x-real-ip":"203.76.219.234","pragma-newtoken":"e7c10bf505535bfddeba94f5c050550adbd9855686816f58f0b5ca08eed6acc6","pragma-appid":"351091731","mkoriginhost":"mobile.dianping.com","pragma-unionid":"91d9c0e21aca4170bf97ab897e5151ae0000000000040786871"}' ...... 

在接口測試類被加載時會進行全局變量賦值,同時替換header裏對應節點的token,測試數據YML文件中則作這樣的描述,每條數據的header則較方便地被替換。

---
Main: 1: &DEFAULT headers: '<%= $v926 %>' host: mobile.51ping.com port: '80' path: "/deliveryaddresslist.ta" search: "?geotype=2&actuallat=31.217329&actuallng=121.415603&initiallat=31.22167778439444&initiallng=121.42671951083571" method: GET query: '{"geotype":"2","actuallat":"31.217329","actuallng":"121.415603","initiallat":"31.22167778439444","initiallng":"121.42671951083571"}' formData: "{}" scheme: 'http:' 2: <<: *DEFAULT headers: '<%= $v930 %>' 3: <<: *DEFAULT headers: '<%= $v940 %>' 4: <<: *DEFAULT headers: '<%= $v950 %>' 5: <<: *DEFAULT headers: '<%= $v990 %>' 

解決RPC接口測試

HTTP接口的測試框架選擇面仍是比較多的,RPC調用的框架如何測試呢?答案就是JRuby + Java的反射調用,在Pigeon接口中咱們已經試點了這種方式,證實是可行的,針對不一樣的RPC框架實現不一樣的Adapter(Jar文件),Coral-API傳參(JSON格式)給Adapter,Adapter經過解析參數進行反射調用,這樣對於框架來講無需改動,只需對部分文件模板稍做調整,也無需在Ruby中混寫Java代碼,實現了最少的代碼量—2行。

rpc調用

rpc調用

 

UI自動化框架Coral-APP

框架思想

App的UI自動化,Ruby的簡便性更明顯,尤爲Appium提供了對Ruby良好的支持,各類UI框架的優劣就不在此贅述了。綜合比較了Appium與Calabash後,選擇了前者,測試框架選用了更適合業務流描述的Cucumber,沿用了之前在Web自動化中使用的對象庫概念,將頁面元素存儲在CSV中,包括了Android與iOS的頁面對象描述,知足不一樣系統平臺的測試須要。在針對微信M站的UI自動化方案中,還需解決微信WebView的切換,及多窗口的切換問題,appium_lib都提供了較好的支持,下面介紹下結合了Appium及Cucumber的自動化框架Coral-APP。

框架結構以下圖:

coral-app

coral-app

 

step_definitions目錄下爲步驟實現,public_step.rb定義了一些公共步驟,好比微信測試須要用到的上下文切換,Webview裏的頁面切換功能,也能夠經過support目錄下的global_method.rb裏新增的Kernel中的方法來實現。

support/native目錄下爲app測試的配置文件,support/web目錄下爲h5測試的配置文件。

support/env.rb 爲啓動文件,主要步驟以下:

$caps = Appium.load_appium_txt file: File.expand_path('../app/appium.txt', __FILE__), verbose: true $caps[:caps].store("chromeOptions",{"androidProcess":"com.tencent.mm:tools"}) $driver = Appium::Driver.new($caps,true) Elements.generate_all_objects Before{$driver.start_driver} After{$driver.quit_driver} 

support/elements下爲對象庫CSV文件,內容以下圖:

對象庫文件

對象庫文件

 

support/elements.rb爲對象庫實現,將CSV中的描述轉換爲Elements模塊中對象的功能,這樣在Page中就能夠直接使用相似「Elements.微信我」 這樣的對象描述了。

......
  
def self.define_ui_object(element) case $caps[:caps][:platformName].downcase when "android" idempotently_define_singleton_method(element["OBJNAME"]){$driver.find_element(:"#{element["ATTRIBUTE"]}","#{element["ANDROID_IDENTITY"]}")} else idempotently_define_singleton_method(element["OBJNAME"]){$driver.find_element(:"#{element["ATTRIBUTE"]}","#{element["IOS_IDENTITY"]}")} end end ...... 

support/pages爲Page層,實現了每一個頁面下的操做,目前把它實現爲Kernel中的方法,採用中文命名,便於閱讀使用。

module Kernel def 點擊我 Elements.微信我.click end def 點擊收藏按鈕 Elements.微信收藏.click end def 點擊收藏項 Elements.微信收藏連接.click end def 點擊收藏中的美團外賣連接 Elements.微信收藏連接URL.click end end 

step裏的步驟咱們能夠這樣寫,封裝好足夠的公共步驟或方法,Case的編寫就是這麼簡單。

When /^進入美團外賣M站首頁$/ do 點擊我 點擊收藏按鈕 點擊收藏項 點擊收藏中的美團外賣連接 等待 5 step "切換到微信Webview" 等待 15 step "切換到美團外賣window" end 

最終Feature內容以下:

Feature: 迴歸下單主流程 打開微信->進入首頁->定位->進入自動化商戶->下單->支付->訂單詳情 Scenario: When 進入美團外賣M站首頁 

相對於其餘的UI測試框架,使用接近天然語言的描述,提升了Case可讀性,編寫上也沒有其餘框架那麼複雜。固然UI自動化中仍是有一些小難點的,尤爲是Hybrid應用,Appium目前還存在些對使用影響不大的Bug,在框架試用完成的狀況下,將在微信入口體驗優化項目結束後的進一步使用中去總結與完善。

質量工做的自動化

都知道在美團點評,QA還擔負着質量控制的工做,當功能+自動化+性能+其餘測試工做於一身,並且是1:8的測試開發比下,如何去關注質量的改進?答案只有:工具化、自動化。開發這樣一個小系統,技術方案選擇上考慮主要是效率和學習成本,符合敏捷開發的特色,基於這些因素,應用了被稱爲「Web開發的最佳實踐」的Rails框架。

Rails的設計有些顛覆傳統的編程理念,CRUD的實現上不用說了,一行命令便可,數據庫層的操做,經過migration搞定,在Mail,Job等功能的實現上也很是方便,框架都有對應的模塊,而且提供了大量的組件,Session、Cookie、安全密碼、郵件地址校驗都有對應的gem,感受不像是在寫代碼,更像是在配置項目,不知不覺,一個系統雛形就完成了,整理了下項目中使用到的gem,主要有如下這些。

前端相關:

  1. bootstrap-sass Bootstrap框架
  2. jquery-rails jQuery框架
  3. simple_form 優化的form組件
  4. chartkick 堪稱一行代碼便可的圖表組件
  5. hightchart 圖表組件

後端相關:

  1. validates_email_format_of 郵件地址校驗
  2. has_secure_password 安全密碼組件
  3. mysql2 MySQL鏈接組件
  4. cancancan 權限管理組件
  5. sidekiq 隊列中間件
  6. sidekiq-cron 定時Job組件
  7. rest-client Http And Rest Client For Ruby
  8. will_paginate 分頁組件

從搭建開發環境、寫Demo,本身作產品、開發、測試、搭建生產環境、部署,邊參閱文檔邊實現,總共18我的日左右,實現了平臺基礎功能、線上故障問題的管理及通知、測試報告的管理及通知、Sonar數據的抽取(Job及郵件)、Bug數據的抽取(Job)、自動化測試項目的接入、質量數據的Dashboard各種數據圖表展現等功能,如下爲系統功能的兩個示例:

後臺管理界面

shwmqp manager

shwmqp manager

 

線下缺陷周趨勢

shwmqp manager

shwmqp manager

 

應用Rails,團隊較快進入了能夠經過數據進行質量分析的初級階段,固然還有很長的路要走,在從0到1的這個過程當中,仍是較多地體會到了敏捷開發的特性,也充分感覺到了DRY理念。

總結

以上爲半年左右時間內,外賣上海QA團隊在自動化工做上的一些實踐,總的來講,達到必定預期效果,整理這篇文章分享一些心得。所謂的主流與小衆並不是絕對,主要從幾個方面衡量:

  1. 應用領域。Ruby由於性能問題,始終不太主流,但並不意味着它一無可取,用在測試領域,開發效率、DSL的友好性、語言的粘合性、使用者的學習低成本,都能發揮很大的優點。
  2. 使用羣體。不一樣的使用羣體對於技能掌握的要求也是不一樣的,能達到一樣效果甚至超過預期則就能夠選擇哪怕「小衆」的方案。
  3. 環境背景。其實有不少初創公司選擇Ruby做爲初期的技術棧有必定的道理,而這與咱們當初的情景有類似之處,實際效果也體現了語言的特性。

固然應用「小衆」技術,必然要面對很多挑戰:如何迅速培養能掌握相關技術的同窗,與其餘語言平臺的銜接問題,面對團隊的質疑等。尤爲Ruby屬於易學難精的那種,從腳本語言應用層次上升到動態語言設計層次仍是須要必定的學習曲線的,也就是說對於使用者來講是簡單的,對於設計者的能力要求較高,就像流傳的Ruby程序員的進階過程就是魔法師的養成史。

正由於有特點的技術,才值得去研究和學習,就像它的設計者所說,目的就是爲了讓開發人員以爲編程是件快樂的事情。作了這麼些年的測試,還可以不中止寫代碼的腳步,也是由於幾年前開始接觸Ruby。不論未來是否成爲主流,它仍然是測試領域工具語言的不錯選擇,無論之後會出現什麼樣的技術,選型的標準也不會改變。技術的世界沒有主流與小衆,只有理解正確與否,應用得當與否。

 

 

美團點評雲真機平臺實踐

背景

隨着美團點評業務愈來愈多,研發團隊愈來愈龐大,對測試手機的需求顯著增加。這對公司來講是一筆不小的開支,但現有測試手機資源分配不均,利用率也很是有限,致使各個團隊開發、測試過程當中都很難作到多機型覆蓋。怎麼樣合理、高效利用這些測試手機資源,是擺在咱們面前的一道難題。

現有的方案

爲了解決這些問題,業內也出現了一些手機管理和在線調試使用的工具或平臺,比較常見的有:

  • OpenSTF
  • 百度MTC的遠程真機調試
  • Testin的雲真機
  • 騰訊WeTest的雲真機
  • 阿里MQC的遠程真機租用

其中OpenSTF是開源項目,其餘的平臺大多也都是基於OpenSTF原理實現的。所以,咱們對OpenSTF項目進行了深刻研究。

遇到的問題

咱們首先按照OpenSTF官方的方案進行了搭建,並進行了小規模的應用,但漸漸的咱們發現了它的一些問題:

  • 模塊過多並且耦合緊密,解耦難度較大,每次修改須要更新全部模塊,難以快速迭代開發。
  • 部分技術選型落後。因爲OpenSTF出現的時間比較早,部分技術已經落後於目前的主流。例如OpenSTF前端選用AngularJS 1.0進行開發,在生態鏈方面已經落後於其餘流行的框架;數據庫方面選用非關係型數據庫RethinkDB,在數據計算和性能方面弱於MySQL等關係型數據庫,同時RethinkDB資料較少,不便於開發與維護。
  • OpenSTF屏幕圖像傳輸採用圖片單張傳輸的方式進行,並且畫質不能由用戶來調節,實際應用中佔用帶寬很高,在網絡比較差的狀況下會有嚴重的卡頓現象,體驗不好。

咱們的方案

架構設計

根據業務場景的須要,並吸收了OpenSTF結構優勢,咱們採用Agent/Server模型的模塊化設計方案。下面分別介紹主要模塊的功能:

  • Agent模塊。Agent模塊與OpenSTF的provider相似,部署在服務器上或者用戶的電腦上,Agent鏈接真實的手機,而且將手機的屏幕圖像經過Websocket動態代理到Websocket服務器上,而後經過消息中心來進行消息的傳遞。
  • Server模塊。Server用來集中管理和調度手機,與OpenSTF結構不一樣的是,咱們的Server端包含Web服務器、Websocket服務器、動態代理以及消息處理服務等部分,Server將用戶的訪問動態代理到對應的Web服務器和Websocket服務器上,並經過消息處理模塊向消息中心傳遞消息,實現用戶與Agent端手機的交互。
  • 數據存儲模塊。數據存儲模塊用來保存整個平臺的數據,例如手機的狀態、用戶使用記錄等。數據存儲模塊由MySQL數據庫和一個RPC服務組成,Server再也不直接讀寫數據庫,而是經過一個RPC服務來進行數據的讀寫操做。
  • 消息中心。與OpenSTF的triproxy功能相似,是鏈接手機和Server的樞紐,消息中心主要處理屏幕的操做以及手機的狀態變動等消息。

經過模塊化設計,項目結構比OpenSTF更加清晰。下面是整個系統的設計圖:

架構的優點

Agent模塊咱們直接複用了OpenSTF的provider大部分功能,包括minicap、minitouch等。在此基礎上,咱們也擴展了一部分OpenSTF缺失的功能,好比:

  • 在provider的基礎上進行了二次開發,使其支持畫質/幀率調節(下文會有詳細說明)。
  • 加入健康檢測功能,檢測手機網絡是否正常、是否設置了網絡代理等。
  • 加入Inspector功能,方便獲取UI控件樹(下文會有詳細說明)。
  • 對Agent進行了版本區分,便於Web端根據不一樣的Agent版本對相應的功能展現和隱藏。

在Server模塊中,咱們引入了動態代理的機制,而且從新開發了Web部分,採用了Vue 2.0 + iView來實現,數據庫採用了MySQL。

相比OpenSTF原生架構,總結下來有如下優點:

  • 模塊耦合程度低,開發和部署更方便。OpenSTF各個功能模塊不只數量多並且代碼耦合緊密,在此基礎上進行二次開發和部署很是困難。而咱們將整個項目分爲Server、Agent、消息中心、數據存儲四個模塊,四個模塊功能和代碼都是獨立的,基本上沒有耦合關係,支持快速迭代開發,部署也很方便。
  • 前端框架更主流,開發和維護成本低。OpenSTF前端是使用AngularJS 1.0實現的,AngularJS 1.0已經處於廢棄階段,各類第三方組件基本已經中止支持,AngularJS 2.0的社區和生態並未成熟,而咱們採用了Vue 2.0前端框架,Vue 2.0相對已經成熟,在美團側也已經有大量應用,可以快速開發高質量的Web功能。
  • 數據庫性能強,設計靈活、維護方便。OpenSTF使用RethikDB做爲數據庫,RethikDB是一個NoSQL型數據庫,它有很是多的缺點,好比處理大量數據時的性能不好,資料很是匱乏,排查問題和數據庫維護都很是困難。而咱們採用了MySQL數據庫,很好的解決了這些問題,而且實現了Server模塊與數據讀寫的分離,這樣在更新數據庫表結構的時候無須同時修改Server端的代碼,只要保證RPC服務的接口格式一致便可,開發和維護更加方便。

除了這些基礎的功能以外,咱們還開發了一些特點的功能,下面咱們來詳細介紹。

特點功能

與客戶端自動化相結合

爲了合理、高效利用測試手機資源,咱們與客戶端自動化進行告終合,主要有兩個方面:

  • 與集團內部的雲測平臺深度融合。在雲測平臺的服務器節點上部署Agent代碼,爲雲測平臺自動化任務建立者提供自動化過程展現和遠程調試功能,同時將雲測平臺空閒的手機開放給更多人使用。
  • 開放API。咱們開放了一些API給普通用戶,供用戶查詢手機狀態、佔用手機、鏈接adb調試等,用戶能夠使用腳本調用API,而後直接在平臺的手機上進行自動化測試。

預定功能

當一臺手機處於繁忙狀態時,用戶必需要等待手機空閒後才能使用,因爲手機空閒時間不肯定,就會給用戶帶來很大的不便。爲了解決這個問題,咱們開發了手機預定的功能,用戶能夠預定處於繁忙狀態的手機,當手機空閒時,自動幫預定用戶佔用15分鐘,並經過即時通信工具通知預定人。

畫質調節

遠程調試平臺的核心是實時獲取屏幕圖像,因爲屏幕傳輸須要比較大的網絡帶寬,在網絡不佳的狀況下就會出現卡頓現象。所以,咱們針對不一樣的網絡作了一些流暢度的優化,下面來介紹一下其中的細節。

屏幕獲取的原理是經過minicap來高速截圖,每秒最高可達60張,而後將這些截圖顯示在Web上。所以,咱們考慮從兩個方面來優化網絡帶寬的佔用,第一個是調節截圖的質量,minicap自己支持調節畫質(OpenSTF固定設置了80%的壓縮比),關鍵代碼以下:

var rate = Number(match[6]) if (rate > 2 && rate < 100) { log.info(rate) if (rate > 30) { options.screenJpegQuality = 80 }else if (rate > 15) { options.screenJpegQuality = 50 }else { options.screenJpegQuality = 20 } frameProducer.restart() framerate = rate } 

第二個是調節每秒發送的圖片張數,也就是幀率,咱們能夠在Agent端控制發送圖片的數量,關鍵代碼以下:

# 首先修改幀率發送部分:
function wsFrameNotifier(frame) { if (latesenttime == 0 || Date.now()-latesenttime > 1000/framerate) { latesenttime = Date.now() return send(frame, { binary: true }) } } # 再加入調整幀率的代碼: case 'rate': var rate = Number(match[6]) if (rate > 2 && rate < 100) { framerate = rate } break 

那麼,幀率和圖片壓縮比調節到多少才能知足不一樣網絡環境的須要呢?咱們先來看一組數據:

圖片壓縮比 圖片尺寸
100% 69.82KB
80% 46.78KB
50% 41.87KB
20% 37.84KB
10% 35.84KB

表中是使用minicap作的圖片壓縮實驗,從數據中咱們能夠看到當圖片質量下降到80%時圖片大小下降比較明顯,而圖片質量並無明顯的降低。繼續下降圖片質量,圖片大小下降有限。咱們再來看另一組數據:

幀率 圖片壓縮比 實際流量
60 100% 4.02M/S
60 80% 2.74M/S
60 50% 2.41M/S
30 80% 1.43M/S
30 50% 1.22M/S
30 20% 1.10M/S
15 50% 0.63M/S
15 20% 0.55M/S
15 10% 0.52M/S

表中是各類幀率和壓縮比組合產生的實際流量數據。

從數據中咱們能夠看到最高幀率和壓縮比的組合下,流量達到了4M/S,而80%壓縮比時流量減少到了2.7M/S,下降很是明顯。考慮到實際網絡狀況,咱們將60幀、80%壓縮做爲了高畫質選項。

而圖片質量從80%下降到50%時圖片大小降低並不明顯,此時下降幀率就成了很好的選擇。當幀率下降到30幀時流量下降了一半,1.2M/S的流量可以知足大部分網絡情況使用,30幀也能保證操做的流暢度,因而30幀、50%壓縮比成爲了中畫質的選項。

低畫質主要是爲了保證在較差的網絡環境可以正常使用,500K/S的流量是紅線。咱們將15幀、20%壓縮比做爲低畫質選項,此時圖片質量和幀率較低,但可以保證基本的使用體驗。

除了經過下降圖片質量和幀率來減少手機屏幕圖像傳輸的流量外,將圖像使用H264等編碼壓縮成視頻傳輸也是一種有效下降流量的辦法,相對於圖片,圖像的壓縮率將會更高,用戶的操做體驗也會更好。可是圖像壓縮編碼原理比較複雜,相關技術咱們還在研究當中。

App Mock

在作App測試過程當中常常須要抓包,通常狀況下,咱們經過修改WiFi的代理而後用抓包工具就能夠實現。可是這樣作的效率比較低,多個工具切換也很是不便。藉助集團的Mock平臺,咱們開發了一鍵Mock功能,可以快速完成相應App的Mock操做。帶來的好處是咱們能夠一邊操做App,一邊查看App發出的請求,大大提升了測試的效率。

App Inspector

App Inspector功能可讓用戶在平臺上使用真機的同時查看頁面控件樹及頁面元素,而且支持Xpath,更加方便高效的查找頁面元素,給UI自動化測試提供了很大便利。

這個功能咱們是藉助Uiautomator實現的。基本原理是寫一個Uiautomator用例,用來獲取當前頁面的Hierarchy,而後將用例打包成一個JAR放到Agent端。當在Web端觸發獲取控件樹時,Agent將JAR包推送到手機上並運行,此時會在手機端生成一個XML文件。而後再使用cat命令獲取XML內容並在前端解析。用例核心代碼以下:

public class launch extends UiAutomatorTestCase { public void testDumpHierarchy() throws UiObjectNotFoundException { File file = new File("/data/local/tmp/local/tmp/uidump.xml"); UiDevice uiDevice = getUiDevice(); String filename = "uidump.xml"; uiDevice.dumpWindowHierarchy(filename); } } 

固然,你也能夠用adb命令來獲取Hierarchy:

adb shell uiautomator dump /data/local/tmp/uidump.xml 

但這種方式不能獲取動態頁面,好比視頻播放頁面。

數據報表

爲了更好的瞭解平臺的運營狀況,咱們作了詳細的數據統計,主要從使用次數、使用時間、設備數量、使用分佈等方面進行統計。目前咱們管理的手機近300臺,平均每月有超過500名研發人員在使用咱們的平臺,天天的使用次數達到280次,天天總使用時長超過60小時。

其餘小功能

除了以上幾個比較大的功能點,咱們也作了一些貼心的小功能,好比:檢測手機網絡是否設置代理、檢測手機已安裝的應用版本及安裝時間、快速安裝最新版本的測試包、支持App內的Schema跳轉等等。這些小功能爲研發人員節省了不少時間,提高了他們的工做效率。

將來規劃

iOS手機支持

目前,雲真機平臺只支持Android手機,對iOS手機的支持正在進行中。咱們已經初步完成了主要功能的開發,預計很快將與你們見面。

產品優化

咱們計劃繼續擴展產品功能,好比支持Log日誌展現和性能數據採集等。目前雲真機平臺已經在美團點評內部平穩運行超過兩年,咱們會繼續不斷迭代版本、打磨產品,提供更好的使用體驗。

 

質量運營在智能支付業務測試中的初步實踐

背景

毋庸置疑,質量是決定產品可否成功、企業可否持續發展的關鍵因素之一。對於「質量時代」下的互聯網企業,如何在快速迭代的節奏中兼顧質量,真正落地「人人重視質量、人人創造質量、人人享受質量」,這是對QA的要求,也是整個產品技術團隊面臨的重要挑戰。

質量運營,是將運營的思路注入到質量評估與改進工做中,它着眼於產品的全生命週期,以質量爲中心,以數據爲驅動,經過建設持續迭代的質量保障體系,最終提高交付質量。本文將聚焦研發過程當中的提測階段,以改進提測質量爲例,從方案制定、策略應用、效果評估等幾個方面,介紹質量運營在智能支付業務中的初步應用。

挑戰

美團點評智能支付承擔了整個公司全部線下交易,當前日交易量已經突破1000萬單,是公司繼外賣和摩拜以後,又一個千萬級日訂單的業務。業務高速增加、團隊快速擴張的狀況下,質量問題極易被放大化,若是不能及時獲得處理,後續解決成本會愈來愈高。

存在的痛點

剛參與智能支付業務測試時遇到的幾個問題,以下:

  1. 缺陷嚴重級別高,提測打回時常發生,如:核心功能未實現或實現與需求不符。
  2. 缺陷數量多,定位、修復、迴歸耗時長,如:越在上游引入的缺陷,修復的成本就越高,潛在的風險也越大。
  3. 各種低級缺陷,團隊彼此間的信任度下降,如:文案錯誤、變量引用錯誤等編碼大意致使的低級缺陷。

解決的難點

在嘗試去改善時發現難以推進的幾個問題,以下:

  1. 對暴露出的質量問題,如何更直觀的在認知上達成一致?如:收到過不少相似的問題反饋:「xx的缺陷太多了,質量意識差」、「xx項目存在很大問題,須要儘快改進」,即便是基於事實得出的判斷,這種偏主觀的表達方式,對問題達成一致的認知帶來很大的困難。
  2. 對已公認的質量問題,如何更快速的進行分析和定位?如:缺陷發生在測試階段,但缺陷的引入多是在需求階段、設計階段、開發階段;某個時間段內的異常質量數據,多是A項目或B項目,多是C團隊或D團隊。問題類型細分、數據鑽取能力等等,在問題的快速分析和定位中相當重要。
  3. 對已定位的質量問題,如何找到能夠落地的改進措施?如:項目總結中經常會見到相似這樣的描述:「增強自測」、「嚴格遵照項目流程」、「文檔須要寫的更詳細些」,這種偏「形容詞」的改進措施,很難實際操做,這也是整個質量改進過程當中最大的一個難點。

思路

質量改進是一個持續迭代的過程,不可急於求成。按照質量運營的方法,基本思路爲:分析痛點,找到抓手,持續運營,造成閉環。

基於提測階段的質量問題特徵,從痛點和難點中尋找突破點。大體思路爲:

  1. 目標應達成一致:質量改進的目標是QA的KPI,並應該與關鍵干係人在願景、目標上達成一致。
  2. 問題的客觀呈現:提取核心度量指標,經過有效數據和典型案例說話。
  3. 數據的靈活鑽取:儘量全的提供各類維度的數據,並分層級展現。
  4. 改進措施可落地:對措施的多方Review、流程標準化到工具化的演進。

解決方案

解決方案的重中之重,是務必遵循PDCA來實現運轉方式的閉環。具體以下:

肯定問題與方向

經過痛點描述可知,缺陷是反映智能支付業務當前提測質量的最顯著特徵。提測質量的進一步分析,可經過缺陷的數量、缺陷的嚴重程度、缺陷的生成緣由三個方向來展開。

缺陷數量

缺陷數量 具體說明
缺陷總數 指定統計規則下缺陷的數量,僅包含項目過程當中提交的缺陷

缺陷的嚴重程度

嚴重級別 具體說明 使用範圍
致命-Blocker 影響核心功能的缺陷 缺陷致使核心業務流程不可用,或產生較大影響
嚴重-Critical 形成較大影響的功能性缺陷 缺陷致使核心業務流程受影響,或致使非核心業務流程不可用
通常-Major 影響較小的功能性缺陷 缺陷致使非核心業務流程受影響,或致使用戶體驗類的問題
提示-Minor 非功能性缺陷 如:不影響正常功能的UI錯誤、無重大歧義的提示錯誤等
建議-Trivial 優化建議 非嚴格意義上的缺陷,一些可優化的點

缺陷的生成緣由

生成緣由 具體說明
實現與文檔不符 RD實現與需求文檔描述不一致
需求缺陷 需求文檔中缺乏相應描述;需求變動
技術方案考慮不足 先後端接口定義不一致;對邊界、異常場景考慮不全等
環境問題 被測服務不穩定;服務器或測試設備配置等引發的問題
第三方依賴 依賴的外部系統引入的問題,如用戶中心等
兼容性 不一樣設備上出現的功能或展現異常類的問題
性能問題 服務端性能:響應時間過長、CPU太高、GC頻繁、沒有分頁、沒有緩存等;
客戶端功耗:包大小、冷啓動時間、流量、內存泄漏OOM、加載時間、耗電量
安全問題 XSS注入,SQL注入等
Bugfix引入 因爲修改Bug引入的缺陷
不是缺陷 無效Bug;不能復現

度量指標及標準

針對缺陷的三個分析方向,提取出可度量的指標、定義合理的標準值,並與整個團隊達成一致。

指標提取策略

  1. 典型性
    • 找最想要解決的問題。不追求全面,只針對Top問題提取指標,如:生成緣由裏最應該避免的是哪些。
    • 找最能反映問題的指標。如:缺陷數量有衆多度量指標(新增數量、人均數量等等),爲排除工做量影響,咱們選擇用千行代碼缺陷率這個指標。
  2. 有效性
    • 除非對絕對數量有明確要求,不然儘可能使用百分比做爲度量指標。
    • 指標數據的計算方式,要求簡單易懂,並務必獲得相關人的承認。

標準制定策略

  1. 基於公司統一要求,如:Sonar千行代碼嚴重問題數,統一標準爲低於0.1。
  2. 基於公司各業務現狀,如:缺陷相關指標按照公司各業務部門排行,取Top5的值做爲標準線。
  3. 基於自身業務階段持續調整,如:隨着智能支付業務質量的持續改進,定義更嚴格的質量標準。

最終定義的指標與標準

度量指標 指標說明 標準值
千行代碼缺陷率 (缺陷總數/代碼行數)* 1000 移動端:< 0.45
前端:< 0.2
後端:< 0.15
Sonar千行代碼嚴重問題數 (Sonar嚴重問題數/代碼行數)* 1000 Blocker:0
總數:< 0.1
嚴重缺陷佔比 嚴重缺陷總數/缺陷總數 < 3.5%
需求缺陷佔比 需求缺陷總數/缺陷總數 < 10%
實現與文檔不符缺陷佔比 實現與文檔不符缺陷總數/缺陷總數 < 10%

獲取數據並展現

基於Metrics(美團點評工程質量中心提供的度量平臺),可以快速的獲取數據並展現。但要注意,部分指標的計算須要對Metrics提供的數據進行二次處理,以保證數據的精準性。如:在計算千行代碼缺陷率時,須要排除掉開發自測缺陷等。

對於數據的展現形式,除了利用Metrics提供的各類圖表外,最爲關鍵的是要實現數據與問題(相關缺陷)的可關聯,以便進行下一步分析。以下圖所示(經過超連接方式進行關聯):

數據與問題可關聯

數據與問題可關聯

 

制定計劃並改進

改進措施的制定和實施是整個質量改進過程當中的重中之重。基於經驗,給出三個策略。

自上而下與自下而上相結合

  • 自上而下:經過有效數據、典型案例,建設可信任的結果評估體系;以此爲基礎,利用每個問題數據,在Leader層強化質量意識,借鑑向上管理的思路,實現質量改進的向下驅動。
  • 自下而上:經過案例覆盤、數據鑽取,對問題進行明肯定位,讓問題方基於工具便可將問題下沉到具體項目或具體角色,進而推動可落地的過程改進,並持續利用結果評估體系衡量改進效果,實現質量改進的向上閉環。

多維度的數據聚合與分析相結合

  • 周維度數據聚合:對週數據中的異常進行分析,並排除掉因週期偏短致使的數據噪點,重在對問題進行風險預警。
  • 月維度數據聚合:對月數據中的異常進行分析,並結合數據的變化趨勢,重在對問題進行確認和改進。周維度和月維度相結合,構成了質量管理中的問題發現與改進週期。
  • 季度維度數據聚合:對季度數據的分析,重在得出對質量目標的完成度並給出質量評分,並對過程當中的問題進行回顧和總結,構成了質量管理中的考覈週期。

流程的標準化與工具化相結合

  • 在改進提測質量的初期階段,對於流程的優化常常出如今各個項目總結的改進措施中,但大可能是經過意識、模板或者口頭提醒來實現,這無疑增長了流程的接入成本、執行難度,進而下降了流程的約束力。
  • 借鑑在製造業中常見的一種解決思路——「防呆措施」,在流程標準化以後,應儘量將其工具化,提高流程的生命力。

  • 防呆措施的目的之一是防止不符合流程的產出物交付到下游。
  • 將防呆措施應用到提測流程,即應實現各項准入標準的自動化檢查,相似以下提測時校驗:

防呆措施

防呆措施

 

測試流程

測試流程

 

回顧與反饋

主要從時間維度、項目維度兩方面開展。

  1. 時間維度,各種週會、雙週會、季度總結,對質量數據進行Review。
  2. 項目維度,重在項目覆盤。覆盤能夠當作PDCA環和環之間的鏈接,有了它,PDCA才能環環相扣、周而復始。

迭代與推廣

若改善有效,則進行推廣。若改善無效,則分析緣由,修改計劃,從新啓動另外一輪PDCA。

  1. 指標與標準的持續迭代,如:過程當中對Sonar千行嚴重問題數的標準由0.1提高到0。
  2. 度量模型與方法工具的推廣,如:質量報表、Sonar在PR時觸發檢查不經過不容許Merge、提測准入自動化等等在其餘業務的推廣。

效果

對於效果的評估,主要從三方面進行說明。

  1. 質量數據的關注度
  2. 質量指標的達成度
  3. 過程質量改進對迭代效率的提高效果

質量數據關注度

主要體如今團隊各方對質量報表的使用率。如下三張圖分別爲:智能支付QA、智能支付RD、智能支付RD Leader對質量報表的使用率走勢。

智能支付QA

智能支付QA

 

智能支付RD

智能支付RD

 

智能支付RD

智能支付RD

 

質量指標達成度

對質量指標的達成狀況進行說明,其中:初始值爲16年Q4的狀況。

度量指標 初始值 標準值 目標完成度
千行代碼缺陷率 移動端:0.7
前端:0.25
後端:0.3
移動端:< 0.45
前端:< 0.2
後端:< 0.15
總體達標,但存在個別方向缺陷率較高
Sonar千行代碼嚴重問題數 Blocker > 0
總數:0.2
Blocker:0
總數:< 0.1
達標
嚴重缺陷佔比 14%左右 < 3.5% 達標
需求缺陷佔比 18%左右 < 10% 達標
實現與文檔不符缺陷佔比 < 10% < 10% 達標,但有升高趨勢,接近標準值

近幾個Q的變化趨勢,以下:

迭代效率提高效果

以客戶端方向爲例(以前過程質量存在較嚴重的問題),說明過程質量改進對迭代效率的提高效果。

總結

通過一段時間的摸索和實踐,咱們在提測質量上有了較明顯的提高,過程當中積累的方法、流程和工具也在推廣使用。但提測質量只是全生命週期質量運營的一小部分,對於高速發展的智能支付業務,不只要求整個質量保證體系的迭代優化,更要求全體成員不斷提高質量思惟、持續追求極致質量,進而造成一種質量文化,真正實現「人人重視質量、人人創造質量、人人享受質量」

相關文章
相關標籤/搜索