接口自動化測試的一點總結


前言

本文是我在公司總結的一點點個人建議, 可能有非常多的遺漏, 先記錄下來這時候我的理解。公司是做共享單車業務的, 所以場景基本上也可以復用, 畢竟大家都騎過單車。注明: 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結合


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM