關於前端接口測試的探索和挖坑

開始

最近幾年,前端測試漸漸被人重視,相關的框架和方法已經比較成熟。
斷言庫有should, expect, chai。 單元測試框架有mocha, jasmine, Qunit。 模擬瀏覽器測試環境有Phantomjs, Slimerjs。 集成測試任務管理工具備karma。此外,還有一堆諸如Selenium、nightwatch(冰火齣戲)等各色思路不一樣的關注UI測試的工具。
本文主要關注的是接口測試。
接口是先後端協做的橋樑,是系統得以順利運行的關鍵。所謂接口測試,就是檢查系統提供的接口是否符合事先撰寫的接口文檔。數據結構是否完備,數據類型和取值是否符合標準。
實際上,接口測試由後端來作會比較方便,可是因爲一些實際緣由(後端大哥比較忙,人手不足等),後端每每不能確保接口數據必定符合接口文檔規定。此時,做爲前端,咱們爲何不能另闢蹊徑,探索一番呢?css

思路分析

接口測試最大的難點是什麼?我以爲是登陸狀態的獲取
衆所周知,一個系統的大部分接口都只會對登陸用戶開放。在測試接口以前,首先必須確保此次會話已經登陸,發送給後臺的請求中必須攜帶登陸後獲取的 cookie。面對這個問題,最直接的想法是在後臺模擬登陸。html

後臺模擬登陸

mocha 能夠運行在node中,理論上咱們徹底能夠在node環境下,使用一些http client( request, superagent等),模擬進行登陸。手動獲取cookie,並加在以後的每一次接口請求中。得到到接口數據後,就能夠結合 mocha,愉快地進行測試了。
但是,實際實驗以後,我發現這個方案存在一些缺陷。前端

  1. 難以封裝複用
    不一樣系統的登陸流程並不相同。至關多的系統要求在登陸時須要附帶其餘的 cookie 或者額外的表單參數。
    以本人測試的系統爲例,登陸時就須要帶上一個 key 爲 jsessionid 的 cookie,以及一個 key 爲 nlt 的表單參數。這個 cookie 是怎麼來的呢?是訪問登陸頁時返回的 set-cookie 頭設置的。這個表單參數又是怎麼來的呢?是藏在登陸頁面的表單中的一個隱藏域。
    因此,若是簡單地用 http client 向登陸地址發一個 post 請求,僅僅帶上本身的用戶名密碼,你就會發現,登陸毫無疑問的···失敗了。
    更煩人的是,若是你的系統登陸依賴 SSO,內部存在 302 請求轉發,那麼頗有可能會出現 cookie 丟失的狀況(有兩個 set-cookie header,瀏覽器能識別並正確設置,可是不少 http client 只能拿到最後一個)。
    咱們固然能夠動用各類奇技淫巧,手動獲取和設置各類特定的 cookie,去網頁裏爬出隱藏域的值。但是,這一切,僅僅對特定的系統有效。若是換一套系統,你就必須從新研究一遍登陸流程,從新寫一遍模擬登錄代碼,感受仍是挺崩潰的。node

  2. 難以應對驗證碼
    上面的問題僅僅只是使用不便,這個問題就是直接就給該方案判了死刑。固然,爬蟲界也有很多應對驗證碼的解決方案,好比依託 OCR 軟件啊,人工判別 API 啦, 更厲害的還有本身作圖像處理和算法進行識別。但是,做爲一個簡單的接口測試,這種方案是否是過小題大作了點?webpack

瀏覽器擴展

mocha 也能夠在瀏覽器環境運行,當後臺模擬登錄遇到困難,咱們很容易想到,在瀏覽器環境進行測試是否可行呢?
普通的瀏覽器環境確實會有必定問題,那就是前端的老大難:跨域
咱們的目的是前端接口測試,原則上不該也不能讓後臺搭配測試工做去改接口,因此,CORS,jsonp 都是不可行的。
難道這條路又堵死了?非也,咱們還有一個選項,那就是——瀏覽器擴展。
以 chrome extension 爲例,只要在 manifest.json 文件中配置好 permissions ,擴展發起的請求就能夠成功跨域。事實證實,徹底沒有問題。不只能夠跨域,還能夠攜帶登陸後的 cookie,因此,只要在瀏覽器正常登陸後,再打開插件相關頁面進行驗證,就能夠解決登陸狀態的問題。簡直完美。web

方案設計

既然定下了方案,下一步就是設計。做爲接口測試的解(wa)決(keng)方(zhi)案(lv),咱們必須具有通用性與易用性。使用者只需提供配置,不須要再進入源代碼修改打包。
本方案中中測試框架和斷言使用 mocha + chai。這方面的資料汗牛充棟,本篇再也不贅言。算法

目錄結構

apiTest
    │  package.json
    │  webpack.conf.js
    │  api.conf.dist.js
    │  api.conf.dist.js.map
    │  index.js
    │  manifest.json
    │  test.png
    ├─config
    │  index.js
    ├─css
    ├─html
    ├─js
    ├─lib
    └─TestCreator

其中,index.js 是入口文件; manifest.json 是 chrome 插件配置文件; config/index.js 是用戶測試配置文件。css, html, js, lib 都用於存放資源文件。chrome

使用流程

  1. 安裝插件(若是已安裝過就能夠省略)npm

  2. 提供測試配置json

  3. 用戶去系統登陸頁完成登陸

  4. 點擊插件圖標,打開新 tab 頁

  5. 在 tab 頁中進行測試,並在頁面上顯示結果

讓咱們從 manifest.json 文件開始,一步一步深刻,看目標流程是如何實現的。

- manifest.json

"permissions": [
    "tabs",
    "http://*/*",
    "https://*/*"
],
"background": {
   "scripts": "js/background.js"
}

在 manifest.json 文件中,定義 background 屬性。定義的 js/background.js 文件將自動在後臺運行。permissions 屬性定義了擴展的權限。「tabs」指明能夠打開瀏覽器自己的 tab 標籤頁,後面兩個配置指明瀏覽器能夠向任何 url 發送請求。(不配置會跨域)


- js/background.js

chrome.browserAction.onClicked.addListener(function(){
  var url = chrome.extension.getURL("../html/main.html");
  window.open(url, "main_page");
})

在 js/background.js 文件中,註冊了一個事件函數。當用戶點擊插件圖標時,打開一個 html/main.html 做爲新的 tab 頁。咱們全部的任務都將在這個 tab 頁中實現。


- html/main.html

<!doctype html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <link rel="stylesheet" type="text/css" href="../css/demo.css">
  <link rel="stylesheet" type="text/css" href="../css/mocha.css">
  <script src="../lib/mocha.js"></script>
  <script src="../config/index.js"></script>
  <script src="../api.conf.dist.js"></script>
</head>
<body>
  <div id="ext-box">
    <button id="startBtn">請在登錄後點擊按鈕開始測試</butotn>
  </div>
  <div id="mocha"></div>
</body>
</html>

在這個 html 中,載入了三個 js 文件。其中,config/index.js 是測試配置文件。api.conf.dist.js 是入口文件經 webpack 打包後的壓縮文件。mocha 之因此獨立載入,是由於在瀏覽器環境中,mocha 必須部署在 window 對象下,因此不能打包進去。核心的邏輯代碼,放在 api.conf.dist.js 文件中。
頁面中放置了一個按鈕和一個 id 爲 mocha 的 div。前者點擊後會觸發 mocha 執行,後者做爲一個容器,用於顯示測試結果。


- index.js

import {expect} from 'chai'
import test from './js/main'

function click(e) {
  mocha.run()
  document.querySelector("#startBtn").style.display = 'none';
}

document.addEventListener('DOMContentLoaded', function () {
  var btn = document.querySelector("#startBtn")
  btn.addEventListener('click', click);
});

mocha && mocha.setup('bdd')
mocha.timeout(4000)

const mainTest = testCreator(window.apiTestConf)
mainTest()

index.js 是打包的入口文件。這裏主要作了兩件事:
第一,爲按鈕定義了一個事件監聽函數,點擊時執行 mocha。
第二,初始化 mocha,設置其執行模式(bdd)和超時時間。
第三,執行 mainTest 函數,在這裏定義了全部測試用例。測試用例根據用戶配置文件動態,這也是核心邏輯。下面將進一步詳述。


測試配置的設計

下面展現本文使用的測試配置:

window.apiTestConf = {
  name:"foo",
  path:"http://baz/japi/platform/",
  common:{
    success: {
      value: true,
      type:["boolean"],
    },
    errorCode: {
      value: [0]
    }
  },
  publicStruc:[
    "results>items",
    "results"
  ],
  apis:{
    AccountCenter:{
      "110620001":{
        name:"獲收貨地址列表",
        fullUrl:false,
        data:{
          length:{
            min:1
          },
          item:{
            area:{
                type:"string"
            },
            areaStr:"string",
            consignee:"string",
            detail:"string",
            id:"number",
            ifDefault:"boolean",
            mobile:["string","number"]
          }
        }
      }
    }
  }
}

測試配置決定了測試用例的組織和測試用例內斷言的編寫。其結構學習了一些表單驗證插件,比表單驗證插件複雜的地方在於,表單驗證僅僅針對一維的單一字段,而接口返回的數據則是具有必定的嵌套結構的。下面對該配置進行簡述。

  • path:接口地址的公共部分。

  • common:對接口返回數據的格式上的公共部分進行驗證。好比 success 必須爲 true,errorcode 必須爲 0 等。

  • publicStruc:接口核心數據部分的路徑。系統將根據該路徑一步步尋找。若是沒找到將會在斷言中報錯。若是定義了多個路徑,則會按順序從前日後查找。

  • apis:核心部分,對接口數據進行驗證。

  • AccountCenter:該 key 可變。在這一層級對接口進行分組,好比 AccountCenter 說明下面定義的是帳戶中心的接口的測試配置。

  • 110620001:該 key 可變。這是真實接口的路徑。該 key 值下的對象,就是針對具體數據結構和字段進行配置了。下面將介紹這部分的配置和驗證規則,可能會有點枯燥,不感興趣的讀者能夠略過不看。

字段驗證規則

字段驗證規則:
字段驗證規則指的是接口下data屬性下定義的規則。是對接口核心數據的存在與否、數據類型和值所作的規定

  1. 基本規則規則

    • 規則僅僅對類型是數字,字符串,布爾值和數組的字段有效,若是要驗證的字段是對象,則不起做用。須要對對象內的屬性(一樣看作字段)作進一步的驗證,而不是對對象自己作驗證。

    • 驗證屬性可寫的值是對象,數組和字符串,其餘類型的值都是非法的

    • 驗證屬性若是是一個空對象,則直接經過。

    • 驗證屬性若是是一個數組或字符串,則視爲 type 處理

    • 驗證屬性若是是一個至少包含了required, value, type三者之一的對象,則進行標準化驗證

  2. required

    • 驗證真實字段必須指定,且必須不爲空字符串(也就是說false,0能經過驗證。)

  3. value

    • 若是 value 是數組,則驗證真實值是否至少等於數組中的某一個值

    • 若是 value 是數字,字符串或者布爾值,驗證真實值與其是否相等

    • 若是 value 是一個對象,則進一步判斷:

      • min:規定最小值,僅僅對數字有效

      • max:規定最大值,僅僅對數字有效

      • not:不爲其值。能夠是一個數組,此時不爲數組中的全部值

      • start:開始字符,僅僅對字符串有效

      • end:結束字符串,僅僅對字符串有效

  4. type

    • type 可寫的值是字符串。這些字符串的可選值爲:"number","string","boolean","array"。沒有"object","undefined","null",由於沒有意義

    • type 能夠是一個數組,數組中的值也是上面的可選值。此時,只要知足數組中的一個值,就能經過驗證

  5. length
    當數據是數組時纔有效,是對數組長度作的驗證

    • min:規定最小值,僅僅對數字有效

    • max:規定最大值,僅僅對數字有效

  6. item

    當數據是數組時纔有效,裏面進一步規定對數組中每一項的驗證

設計完各類規則後,接下來就是依樣畫葫蘆地編寫代碼了。因爲代碼量比較多,這裏就再也不贅述。其核心思想就是根據配置項生成各類測試用例和斷言。最後供 mocha 運行,輸出結果。

clipboard.png

結束和展望

本文所設計的方案基本可以知足前端接口測試的要求,但仍是有一些缺陷,弊端,及有待改進的地方。

  1. 驗證規則涉及不夠全面和嚴密,有待豐富,

  2. 能夠將整體目錄結構以及內部的 TestCreater 封裝成 npm 包,更方便使用。

  3. 測試經過時,沒法看到經過了哪些斷言。測試失敗時,只輸出未經過的第一條斷言的信息。輸出信息不夠全面豐富。這必定程度上是 mocha 和 chai自己的特性,不知道有什麼方式能夠優化。

最後,本文中若出現了錯誤,或是讀者有更好的方案,望不吝嗇賜教。

相關文章
相關標籤/搜索