前言
本文是我在公司總結的一點點個人建議, 可能有非常多的遺漏, 先記錄下來這時候我的了解。公司是做共享單車業務的, 是以場景基本上也可以複用, 畢竟大家都騎過單車。注明: code是我司接口傳回的标志。
編寫之前
-
接口相關(這塊總結不全)
了解接口的功能及其使用場景(正常/異常)及接口具體做的事情。
- 接口實作了什麼功能
- 接口是否有操作了資料庫對應字段
- 接口是否有操作了redis對應key
-
接口的入參
包括必填項和選填項丢失/多餘帶來的影響, 入參字段的長度是否有限制, 如身份證姓名等
-
接口的出參
包括正常/異常場景下code, msg等字段的校驗, 如有傳回資料, 對傳回資料的校驗如何去做
-
接口的設計是否符合功能的預期
如資料不允許重複時, 連續調用接口2次是否會插入2條資料
- 場景準備
-
掌握每個場景所需要的前置條件
如關鎖接口在 正常使用時,他的前置條件為該車輛的鎖已經打開。
-
考慮如何設計場景
可選擇資料庫/redis添加測試資料或調用接口新增資料的辦法(==接口之間會存在依賴, 一旦添加資料的接口出錯, 此場景也無法驗證==)
-
- 用例資料準備
-
盡可能的動态準備測試資料
如車輛編号, 可選擇從資料庫撈取。如有身份證号+姓名這種較為複雜的資料, 可寫在變量裡。但需要多挑選幾組資料, 随機讀取
-
資料依賴
優先采取新增資料的方式, 保證之前資料完好, 新增資料如有name等字段, 可帶上特定辨別+時間戳的方式。在用例執行完成之後将其清除, 如果出現垃圾資料, 也便于使用定時任務進行清理。
- 盡量不要把資料寫死
-
-
斷言
對比較重要的字段作斷言, 如需要展示給使用者的字段。
- http狀态碼校驗
- code/msg校驗
-
db校驗(業務相關, 如無類似情況可忽略)
存在接口名傳回與資料庫不一緻的情形, 應以接口為主。db目前多使用下劃線式, 接口出參常使用駝峰式。編寫sql查詢語句的時候, 使用
此類。select ride_type as rideType
-
異常場景db校驗
為了防止: 接口出參傳回code不為0, 但db卻被修改。
-
redis校驗
如有涉及到redis, 需要對redis字段做斷言。
-
最近比較火的異步接口
異步接口如何做斷言, 本人沒有太多接觸。由于http協定是無狀态的, 異步接口一般是調用後将任務放入消息隊列, 接口就成功傳回了。我的了解是去檢查消息隊列是否存在消息, 如有如果被消費了, 可起一個收尾類似tearDown的用例專門針對異步接口, 當他們消費完畢之後, 再對資料庫/redis進行相關校驗。
開始編碼
-
編碼
gat是公司内部封裝的基于golang的自動化測試架構, 其實隻封裝了http請求和做了一部分單元測試架構的工作。
-
用例描述
用例編寫之前, 腦海裡應該有以下幾點。如何設計場景, 覆寫哪些場景, 如何做斷言。可以在檔案頂部, 寫入自己的思路, 這樣在編碼過程中會遊刃有餘, 不至于亂了方寸。之後維護的時候也不至于被業務邏輯繞暈。
-
setUp和tearDown
目前gat架構是由TestFuncName為入口, 我們可以在函數開始執行後, 調用setUp()函數, 将自己想處理, 想得到的資料都處理完成。再後面就是邏輯的代碼, 到最後使用tearDown進行清理。
- 用例名稱與Action對應, 檔案名盡量與結構體名一緻
- 大體結構
- 注釋要多寫, 常用方法可以封裝
/* 測試功能點: 檢查使用者行程 覆寫到的場景: 1. 使用者正在騎行中 2. 使用者未騎行 資料準備: 這裡填寫, 你将怎樣制作資料 資料清理: 這裡填寫, 你将如何清理髒資料 用例執行流程: 這裡寫你的執行思路, 首先檢測什麼測試點, 然後.... 斷言: 寫出斷言的标準, 理由, 如何做(這也是評審的一部分) */ package UserCenter import ( "fmt" "testing" ) type struct UserRideCheck { Data []map[string]interface{} // 測試資料 Action string //調用接口名 } func (u *UserRideCheck) setUp() { fmt.Println("用例正準備執行!") } func (u *UserRideCheck) tearDown() { fmt.Println("用例執行完畢, 正在清理!") } func (u *UserRideCheck) TestUserRideCheck() { setUp() // 初始化 //主邏輯, 可再封裝函數 defer tearDown() // 清理(後續可添加Recovery防止用例失敗阻塞) } func init() { // 自己架構添加用例的邏輯 data := initStruct() testcase.Cases["UserCenter"] = append(testcase.Cases["UserCenter"], data) } func initStruct() *UserRideCheck{ return &UserRideCheck { Action: "user.ride.check" } } // unittest func UnitTestUserRideCheck(t *testing.T) { u := initStruct() u.TestUserRideCheck() }
-
附加:
- 如果可能的話, 對開發做代碼走查, 盡可能覆寫其if else分支
- 我們自身的代碼也會出錯, 我們需要用日志記錄測試過程中接口出現的問題以及自己的問題
- 如果可以, 與CI結合