摘要:本文主要關注的是接口測試。所謂接口測試,就是檢查系統提供的接口是否符合事先撰寫的接口文檔。作為接口測試的解決方案,我們必須具備通用性與易用性。
開始
最近幾年,前端測試漸漸被人重視,相關的框架和方法已經比較成熟。
斷言庫有should, expect, chai。 單元測試框架有mocha, jasmine, Qunit。 模擬瀏覽器測試環境有Phantomjs, Slimerjs。 集成測試任務管理工具有karma。此外,還有一堆諸如Selenium、nightwatch(冰火出戲)等各色思路不同的關注UI測試的工具。
本文主要關注的是接口測試。
接口是前后端協作的橋梁,是系統得以順利運行的關鍵。所謂接口測試,就是檢查系統提供的接口是否符合事先撰寫的接口文檔。數據結構是否完備,數據類型和取值是否符合標準。
實際上,接口測試由后端來做會比較方便,但是由于一些實際原因(后端大哥比較忙,人手不足等),后端往往不能確保接口數據一定符合接口文檔規定。此時,作為前端,我們為什么不能另辟蹊徑,探索一番呢?
接口測試最大的難點是什么?我覺得是登錄狀態的獲取。
眾所周知,一個系統的大部分接口都只會對登錄用戶開放。在測試接口之前,首先必須確保這次會話已經登錄,發送給后臺的請求中必須攜帶登錄后獲取的 cookie。面對這個問題,最直接的想法是在后臺模擬登錄。
mocha 可以運行在node中,理論上我們完全可以在node環境下,使用一些http client( request, superagent等),模擬進行登錄。手動獲取cookie,并加在之后的每一次接口請求中。獲得到接口數據后,就可以結合 mocha,愉快地進行測試了。
可是,實際實驗之后,我發現這個方案存在一些缺陷。
難以封裝復用
不同系統的登錄流程并不相同。相當多的系統要求在登錄時需要附帶其他的 cookie 或者額外的表單參數。
以本人測試的系統為例,登錄時就需要帶上一個 key 為 jsessionid 的 cookie,以及一個 key 為 nlt 的表單參數。這個 cookie 是怎么來的呢?是訪問登錄頁時返回的 set-cookie 頭設置的。這個表單參數又是怎么來的呢?是藏在登錄頁面的表單中的一個隱藏域。
所以,如果簡單地用 http client 向登錄地址發一個 post 請求,僅僅帶上自己的用戶名密碼,你就會發現,登錄毫無疑問的···失敗了。
更煩人的是,如果你的系統登錄依賴 SSO,內部存在 302 請求轉發,那么很有可能會出現 cookie 丟失的情況(有兩個 set-cookie header,瀏覽器能識別并正確設置,但是很多 http client 只能拿到最后一個)。
我們當然可以動用各種奇技淫巧,手動獲取和設置各種特定的 cookie,去網頁里爬出隱藏域的值。可是,這一切,僅僅對特定的系統有效。如果換一套系統,你就必須重新研究一遍登錄流程,重新寫一遍模擬登陸代碼,感覺還是挺崩潰的。
難以應對驗證碼
上面的問題僅僅只是使用不便,這個問題就是直接就給該方案判了死刑。當然,爬蟲界也有不少應對驗證碼的解決方案,比如依托 OCR 軟件啊,人工判別 API 啦, 更厲害的還有自己做圖像處理和算法進行識別。可是,作為一個簡單的接口測試,這種方案是不是太小題大做了點?
mocha 也可以在瀏覽器環境運行,當后臺模擬登陸遇到困難,我們很容易想到,在瀏覽器環境進行測試是否可行呢?
普通的瀏覽器環境確實會有一定問題,那就是前端的老大難:跨域。
我們的目的是前端接口測試,原則上不應也不能讓后臺搭配測試工作去改接口,所以,CORS,jsonp 都是不可行的。
難道這條路又堵死了?非也,我們還有一個選項,那就是——瀏覽器擴展。
以 chrome extension 為例,只要在 manifest.json 文件中配置好 permissions ,擴展發起的請求就可以成功跨域。事實證明,完全沒有問題。不僅可以跨域,還可以攜帶登錄后的 cookie,所以,只要在瀏覽器正常登錄后,再打開插件相關頁面進行驗證,就可以解決登錄狀態的問題。簡直完美。
既然定下了方案,下一步就是設計。作為接口測試的解(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 都用于存放資源文件。
使用流程安裝插件(如果已安裝過就可以省略)
提供測試配置
用戶去系統登錄頁完成登錄
點擊插件圖標,打開新 tab 頁
在 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
在這個 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屬性下定義的規則。是對接口核心數據的存在與否、數據類型和值所做的規定
基本規則規則
規則僅僅對類型是數字,字符串,布爾值和數組的字段有效,如果要驗證的字段是對象,則不起作用。需要對對象內的屬性(同樣看做字段)做進一步的驗證,而不是對對象本身做驗證。
驗證屬性可寫的值是對象,數組和字符串,其他類型的值都是非法的
驗證屬性如果是一個空對象,則直接通過。
驗證屬性如果是一個數組或字符串,則視為 type 處理
驗證屬性如果是一個至少包含了required, value, type三者之一的對象,則進行標準化驗證
required
驗證真實字段必須指定,且必須不為空字符串(也就是說false,0能通過驗證。)
value
如果 value 是數組,則驗證真實值是否至少等于數組中的某一個值
如果 value 是數字,字符串或者布爾值,驗證真實值與其是否相等
如果 value 是一個對象,則進一步判斷:
min:規定最小值,僅僅對數字有效
max:規定最大值,僅僅對數字有效
not:不為其值。可以是一個數組,此時不為數組中的所有值
start:開始字符,僅僅對字符串有效
end:結束字符串,僅僅對字符串有效
type
type 可寫的值是字符串。這些字符串的可選值為:"number","string","boolean","array"。沒有"object","undefined","null",因為沒有意義
type 可以是一個數組,數組中的值也是上面的可選值。此時,只要滿足數組中的一個值,就能通過驗證
length
當數據是數組時才有效,是對數組長度做的驗證
min:規定最小值,僅僅對數字有效
max:規定最大值,僅僅對數字有效
item
當數據是數組時才有效,里面進一步規定對數組中每一項的驗證
設計完各種規則后,接下來就是依樣畫葫蘆地編寫代碼了。由于代碼量比較多,這里就不再贅述。其核心思想就是根據配置項生成各種測試用例和斷言。最后供 mocha 運行,輸出結果。
結束和展望本文所設計的方案基本能夠滿足前端接口測試的要求,但還是有一些缺陷,弊端,及有待改進的地方。
驗證規則涉及不夠全面和嚴密,有待豐富,
可以將總體目錄結構以及內部的 TestCreater 封裝成 npm 包,更方便使用。
測試通過時,無法看到通過了哪些斷言。測試失敗時,只輸出未通過的第一條斷言的信息。輸出信息不夠全面豐富。這一定程度上是 mocha 和 chai本身的特性,不知道有什么方式可以優化。
最后,本文中若出現了錯誤,或是讀者有更好的方案,望不吝嗇賜教。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83145.html
摘要:本文主要關注的是接口測試。所謂接口測試,就是檢查系統提供的接口是否符合事先撰寫的接口文檔。作為接口測試的解決方案,我們必須具備通用性與易用性。 開始 最近幾年,前端測試漸漸被人重視,相關的框架和方法已經比較成熟。斷言庫有should, expect, chai。 單元測試框架有mocha, jasmine, Qunit。 模擬瀏覽器測試環境有Phantomjs, Slimerjs。 集...
摘要:綜合以上問題得出以下結論業務處理失敗消息要以的方式向上傳遞給調用者業務處理失敗消息以參數的方式傳遞不是很適合,并且不能以的方式返回再次思考,最終從里面想到了一點思路幸好是出身。 我需要拍磚 和 看見你們的意見,為團隊少挖坑 場景:創建訂單 實際流程: 終端調用(PC端、移動端APP、微信端、Web端)-->控制器 或 接口-->實際的業務處理-->控制器 或 接口-...
摘要:,在后續測試時遇到一個詭異,當文件過大時,任務腳本上傳到七牛云失敗。當我遇到大文件無法上傳到七牛云時,斷點調試到這里,發現返回的是。后來還真被我找到了,七牛云官方提供一個腳本工具。 業務場景 需求 我們項目有一個文件上傳需求,需要從客戶端上傳到七牛云的對象存儲和自己的應用服務器上。這里使用七牛云主要是實現下載分發。應用服務器需要留一份是因為后續需要做文件分析(并且是上傳后需要立馬分析出...
摘要:將品牌的標價全部加蘇南的專欄交流公眾號不會對空數組進行檢測。方法用于調用數組的每個元素,并將元素傳遞給回調函數。 showImg(https://segmentfault.com/img/bVblSSO?w=1008&h=298); 前言: ? 今天我想分享一個有關于循環篩選的知識點,也許是前端小白的你首先想到的是用for循環做篩選,但我這種小菜鳥想到的就是map(工作中很喜歡...
摘要:將品牌的標價全部加蘇南的專欄交流公眾號不會對空數組進行檢測。方法用于調用數組的每個元素,并將元素傳遞給回調函數。 showImg(https://segmentfault.com/img/bVblSSO?w=1008&h=298); 前言: ? 今天我想分享一個有關于循環篩選的知識點,也許是前端小白的你首先想到的是用for循環做篩選,但我這種小菜鳥想到的就是map(工作中很喜歡...
閱讀 1013·2021-11-25 09:43
閱讀 1675·2019-08-30 13:59
閱讀 1600·2019-08-30 11:22
閱讀 2130·2019-08-30 11:06
閱讀 1305·2019-08-28 17:51
閱讀 3732·2019-08-26 12:12
閱讀 785·2019-08-26 12:11
閱讀 453·2019-08-26 12:10